From 59c020ee507f3d24c887f6add38f30384c4c7d64 Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Mon, 15 Jul 2019 09:50:03 +0200 Subject: [PATCH] Reformat all files with isort and black --- docs/_ext/djangodummy/settings.py | 8 +- docs/conf.py | 153 +- example/example/settings.py | 127 +- example/example/urls.py | 4 +- example/example/wsgi.py | 6 +- example/orders/admin.py | 11 +- example/orders/migrations/0001_initial.py | 155 +- example/orders/models.py | 9 +- example/pexp/admin.py | 13 +- example/pexp/management/commands/p2cmd.py | 45 +- example/pexp/management/commands/pcmd.py | 19 +- example/pexp/management/commands/polybench.py | 32 +- .../commands/polymorphic_create_test_data.py | 4 +- example/pexp/migrations/0001_initial.py | 324 +- example/pexp/models.py | 11 +- polymorphic/__init__.py | 1 - polymorphic/admin/__init__.py | 56 +- polymorphic/admin/childadmin.py | 83 +- polymorphic/admin/filters.py | 12 +- polymorphic/admin/forms.py | 11 +- polymorphic/admin/generic.py | 29 +- polymorphic/admin/helpers.py | 57 +- polymorphic/admin/inlines.py | 58 +- polymorphic/admin/parentadmin.py | 162 +- polymorphic/base.py | 92 +- polymorphic/compat.py | 23 +- polymorphic/contrib/extra_views.py | 38 +- polymorphic/contrib/guardian.py | 6 +- polymorphic/formsets/__init__.py | 41 +- polymorphic/formsets/generic.py | 106 +- polymorphic/formsets/models.py | 283 +- polymorphic/managers.py | 21 +- polymorphic/models.py | 127 +- polymorphic/query.py | 107 +- polymorphic/query_translate.py | 105 +- polymorphic/showfields.py | 87 +- .../templatetags/polymorphic_admin_tags.py | 19 +- .../templatetags/polymorphic_formset_tags.py | 28 +- polymorphic/tests/admintestcase.py | 88 +- polymorphic/tests/migrations/0001_initial.py | 2618 +++++++++++------ polymorphic/tests/models.py | 90 +- polymorphic/tests/test_admin.py | 109 +- polymorphic/tests/test_contrib.py | 14 +- polymorphic/tests/test_multidb.py | 64 +- polymorphic/tests/test_orm.py | 854 +++--- polymorphic/tests/test_regression.py | 14 +- polymorphic/tests/test_utils.py | 36 +- polymorphic/utils.py | 19 +- runtests.py | 108 +- setup.py | 1 - 50 files changed, 4069 insertions(+), 2419 deletions(-) diff --git a/docs/_ext/djangodummy/settings.py b/docs/_ext/djangodummy/settings.py index 849666a..4903db0 100644 --- a/docs/_ext/djangodummy/settings.py +++ b/docs/_ext/djangodummy/settings.py @@ -5,11 +5,9 @@ # so the docs root won't be detected by find_packages() # Display sane URLs in the docs: -STATIC_URL = '/static/' +STATIC_URL = "/static/" # Avoid error for missing the secret key -SECRET_KEY = 'docs' +SECRET_KEY = "docs" -INSTALLED_APPS = [ - 'django.contrib.contenttypes', -] +INSTALLED_APPS = ["django.contrib.contenttypes"] diff --git a/docs/conf.py b/docs/conf.py index a93456c..fbd9fed 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,173 +11,174 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys import os +import sys + import django import sphinx_rtd_theme # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('_ext')) -sys.path.insert(0, os.path.abspath('..')) -os.environ['DJANGO_SETTINGS_MODULE'] = 'djangodummy.settings' +sys.path.insert(0, os.path.abspath("_ext")) +sys.path.insert(0, os.path.abspath("..")) +os.environ["DJANGO_SETTINGS_MODULE"] = "djangodummy.settings" django.setup() # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.graphviz', - 'sphinx.ext.intersphinx', - 'sphinxcontrib_django', + "sphinx.ext.autodoc", + "sphinx.ext.graphviz", + "sphinx.ext.intersphinx", + "sphinxcontrib_django", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'django-polymorphic' -copyright = u'2013, Bert Constantin, Chris Glass, Diederik van der Boor' +project = u"django-polymorphic" +copyright = u"2013, Bert Constantin, Chris Glass, Diederik van der Boor" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '2.0.3' +version = "2.0.3" # The full version, including alpha/beta/rc tags. -release = '2.0.3' +release = "2.0.3" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'django-polymorphicdoc' +htmlhelp_basename = "django-polymorphicdoc" # -- Options for LaTeX output -------------------------------------------------- @@ -185,10 +186,8 @@ htmlhelp_basename = 'django-polymorphicdoc' latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. #'preamble': '', } @@ -196,29 +195,34 @@ latex_elements = { # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'django-polymorphic.tex', u'django-polymorphic Documentation', - u'Bert Constantin, Chris Glass, Diederik van der Boor', 'manual'), + ( + "index", + "django-polymorphic.tex", + u"django-polymorphic Documentation", + u"Bert Constantin, Chris Glass, Diederik van der Boor", + "manual", + ) ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output -------------------------------------------- @@ -226,12 +230,17 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'django-polymorphic', u'django-polymorphic Documentation', - [u'Bert Constantin, Chris Glass, Diederik van der Boor'], 1) + ( + "index", + "django-polymorphic", + u"django-polymorphic Documentation", + [u"Bert Constantin, Chris Glass, Diederik van der Boor"], + 1, + ) ] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ @@ -240,26 +249,32 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'django-polymorphic', u'django-polymorphic Documentation', - u'Bert Constantin, Chris Glass, Diederik van der Boor', 'django-polymorphic', 'One line description of project.', - 'Miscellaneous'), + ( + "index", + "django-polymorphic", + u"django-polymorphic Documentation", + u"Bert Constantin, Chris Glass, Diederik van der Boor", + "django-polymorphic", + "One line description of project.", + "Miscellaneous", + ) ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { #'http://docs.python.org/': None, - 'https://docs.djangoproject.com/en/stable': 'https://docs.djangoproject.com/en/stable/_objects', + "https://docs.djangoproject.com/en/stable": "https://docs.djangoproject.com/en/stable/_objects" } # autodoc settings -autodoc_member_order = 'groupwise' +autodoc_member_order = "groupwise" diff --git a/example/example/settings.py b/example/example/settings.py index 58e4f35..39d6d87 100644 --- a/example/example/settings.py +++ b/example/example/settings.py @@ -10,105 +10,102 @@ MANAGERS = ADMINS PROJECT_ROOT = os.path.dirname(os.path.dirname(__file__)) DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(PROJECT_ROOT, 'example.db'), + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": os.path.join(PROJECT_ROOT, "example.db"), } } SITE_ID = 1 # Make this unique, and don't share it with anybody. -SECRET_KEY = '5$f%)&a4tc*bg(79+ku!7o$kri-duw99@hq_)va^_kaw9*l)!7' +SECRET_KEY = "5$f%)&a4tc*bg(79+ku!7o$kri-duw99@hq_)va^_kaw9*l)!7" # Language # TIME_ZONE = 'America/Chicago' -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" USE_I18N = True USE_L10N = True USE_TZ = True # Paths -MEDIA_ROOT = '' -MEDIA_URL = '/media/' -STATIC_ROOT = '' -STATIC_URL = '/static/' +MEDIA_ROOT = "" +MEDIA_URL = "/media/" +STATIC_ROOT = "" +STATIC_URL = "/static/" # Apps STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + "django.contrib.staticfiles.finders.FileSystemFinder", + "django.contrib.staticfiles.finders.AppDirectoriesFinder", ) MIDDLEWARE = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', + "django.middleware.common.CommonMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", ) -TEMPLATES=[{ - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": (), - "OPTIONS": { - "loaders": ( - "django.template.loaders.filesystem.Loader", - "django.template.loaders.app_directories.Loader", - ), - "context_processors": ( - "django.template.context_processors.debug", - "django.template.context_processors.i18n", - "django.template.context_processors.media", - "django.template.context_processors.request", - "django.template.context_processors.static", - "django.contrib.messages.context_processors.messages", - "django.contrib.auth.context_processors.auth", - ), - }, -}] +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": (), + "OPTIONS": { + "loaders": ( + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + ), + "context_processors": ( + "django.template.context_processors.debug", + "django.template.context_processors.i18n", + "django.template.context_processors.media", + "django.template.context_processors.request", + "django.template.context_processors.static", + "django.contrib.messages.context_processors.messages", + "django.contrib.auth.context_processors.auth", + ), + }, + } +] -ROOT_URLCONF = 'example.urls' +ROOT_URLCONF = "example.urls" -WSGI_APPLICATION = 'example.wsgi.application' +WSGI_APPLICATION = "example.wsgi.application" INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.admin', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - - 'polymorphic', # needed if you want to use the polymorphic admin - 'pexp', # this Django app is for testing and experimentation; not needed otherwise - 'orders', + "django.contrib.auth", + "django.contrib.admin", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "polymorphic", # needed if you want to use the polymorphic admin + "pexp", # this Django app is for testing and experimentation; not needed otherwise + "orders", ) -TEST_RUNNER = 'django.test.runner.DiscoverRunner' # silence system checks +TEST_RUNNER = "django.test.runner.DiscoverRunner" # silence system checks # Logging configuration LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse' + "version": 1, + "disable_existing_loggers": False, + "filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}}, + "handlers": { + "mail_admins": { + "level": "ERROR", + "filters": ["require_debug_false"], + "class": "django.utils.log.AdminEmailHandler", } }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' + "loggers": { + "django.request": { + "handlers": ["mail_admins"], + "level": "ERROR", + "propagate": True, } }, - 'loggers': { - 'django.request': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': True, - }, - } } diff --git a/example/example/urls.py b/example/example/urls.py index 46bf8dc..6d646f2 100644 --- a/example/example/urls.py +++ b/example/example/urls.py @@ -6,6 +6,6 @@ from django.views.generic import RedirectView admin.autodiscover() urlpatterns = [ - url(r'^admin/', admin.site.urls), - url(r'^$', RedirectView.as_view(url=reverse_lazy('admin:index'), permanent=False)), + url(r"^admin/", admin.site.urls), + url(r"^$", RedirectView.as_view(url=reverse_lazy("admin:index"), permanent=False)), ] diff --git a/example/example/wsgi.py b/example/example/wsgi.py index 9b42e63..1af2c1b 100644 --- a/example/example/wsgi.py +++ b/example/example/wsgi.py @@ -15,12 +15,14 @@ framework. """ import os -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") - # This application object is used by any WSGI server configured to use this # file. This includes Django's development server, if the WSGI_APPLICATION # setting points here. from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") + + application = get_wsgi_application() # Apply WSGI middleware here. diff --git a/example/orders/admin.py b/example/orders/admin.py index 755c3ad..f490fc9 100644 --- a/example/orders/admin.py +++ b/example/orders/admin.py @@ -1,7 +1,8 @@ from django.contrib import admin from polymorphic.admin import PolymorphicInlineSupportMixin, StackedPolymorphicInline -from .models import Order, Payment, CreditCardPayment, BankPayment, SepaPayment + +from .models import BankPayment, CreditCardPayment, Order, Payment, SepaPayment class CreditCardPaymentInline(StackedPolymorphicInline.Child): @@ -24,11 +25,7 @@ class PaymentInline(StackedPolymorphicInline): """ model = Payment - child_inlines = ( - CreditCardPaymentInline, - BankPaymentInline, - SepaPaymentInline, - ) + child_inlines = (CreditCardPaymentInline, BankPaymentInline, SepaPaymentInline) @admin.register(Order) @@ -39,5 +36,5 @@ class OrderAdmin(PolymorphicInlineSupportMixin, admin.ModelAdmin): To make sure the inlines are properly handled, the ``PolymorphicInlineSupportMixin`` is needed to """ - inlines = (PaymentInline,) + inlines = (PaymentInline,) diff --git a/example/orders/migrations/0001_initial.py b/example/orders/migrations/0001_initial.py index daf2861..8e9ce6f 100644 --- a/example/orders/migrations/0001_initial.py +++ b/example/orders/migrations/0001_initial.py @@ -6,83 +6,148 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ] + dependencies = [("contenttypes", "0002_remove_content_type_name")] operations = [ migrations.CreateModel( - name='Order', + name="Order", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('title', models.CharField(max_length=200, verbose_name='Title')), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("title", models.CharField(max_length=200, verbose_name="Title")), ], options={ - 'ordering': ('title',), - 'verbose_name': 'Organisation', - 'verbose_name_plural': 'Organisations', + "ordering": ("title",), + "verbose_name": "Organisation", + "verbose_name_plural": "Organisations", }, ), migrations.CreateModel( - name='Payment', + name="Payment", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('currency', models.CharField(default=b'USD', max_length=3)), - ('amount', models.DecimalField(max_digits=10, decimal_places=2)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("currency", models.CharField(default=b"USD", max_length=3)), + ("amount", models.DecimalField(max_digits=10, decimal_places=2)), ], - options={ - 'verbose_name': 'Payment', - 'verbose_name_plural': 'Payments', - }, + options={"verbose_name": "Payment", "verbose_name_plural": "Payments"}, ), migrations.CreateModel( - name='BankPayment', + name="BankPayment", fields=[ - ('payment_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, on_delete=models.CASCADE, to='orders.Payment')), - ('bank_name', models.CharField(max_length=100)), - ('swift', models.CharField(max_length=20)), + ( + "payment_ptr", + models.OneToOneField( + parent_link=True, + auto_created=True, + primary_key=True, + serialize=False, + on_delete=models.CASCADE, + to="orders.Payment", + ), + ), + ("bank_name", models.CharField(max_length=100)), + ("swift", models.CharField(max_length=20)), ], options={ - 'verbose_name': 'Bank Payment', - 'verbose_name_plural': 'Bank Payments', + "verbose_name": "Bank Payment", + "verbose_name_plural": "Bank Payments", }, - bases=('orders.payment',), + bases=("orders.payment",), ), migrations.CreateModel( - name='CreditCardPayment', + name="CreditCardPayment", fields=[ - ('payment_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, on_delete=models.CASCADE, to='orders.Payment')), - ('card_type', models.CharField(max_length=10)), - ('expiry_month', models.PositiveSmallIntegerField(choices=[(1, 'jan'), (2, 'feb'), (3, 'mar'), (4, 'apr'), (5, 'may'), (6, 'jun'), (7, 'jul'), (8, 'aug'), (9, 'sep'), (10, 'oct'), (11, 'nov'), (12, 'dec')])), - ('expiry_year', models.PositiveIntegerField()), + ( + "payment_ptr", + models.OneToOneField( + parent_link=True, + auto_created=True, + primary_key=True, + serialize=False, + on_delete=models.CASCADE, + to="orders.Payment", + ), + ), + ("card_type", models.CharField(max_length=10)), + ( + "expiry_month", + models.PositiveSmallIntegerField( + choices=[ + (1, "jan"), + (2, "feb"), + (3, "mar"), + (4, "apr"), + (5, "may"), + (6, "jun"), + (7, "jul"), + (8, "aug"), + (9, "sep"), + (10, "oct"), + (11, "nov"), + (12, "dec"), + ] + ), + ), + ("expiry_year", models.PositiveIntegerField()), ], options={ - 'verbose_name': 'Credit Card Payment', - 'verbose_name_plural': 'Credit Card Payments', + "verbose_name": "Credit Card Payment", + "verbose_name_plural": "Credit Card Payments", }, - bases=('orders.payment',), + bases=("orders.payment",), ), migrations.CreateModel( - name='SepaPayment', + name="SepaPayment", fields=[ - ('payment_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, on_delete=models.CASCADE, to='orders.Payment')), - ('iban', models.CharField(max_length=34)), - ('bic', models.CharField(max_length=11)), + ( + "payment_ptr", + models.OneToOneField( + parent_link=True, + auto_created=True, + primary_key=True, + serialize=False, + on_delete=models.CASCADE, + to="orders.Payment", + ), + ), + ("iban", models.CharField(max_length=34)), + ("bic", models.CharField(max_length=11)), ], options={ - 'verbose_name': 'Bank Payment', - 'verbose_name_plural': 'Bank Payments', + "verbose_name": "Bank Payment", + "verbose_name_plural": "Bank Payments", }, - bases=('orders.payment',), + bases=("orders.payment",), ), migrations.AddField( - model_name='payment', - name='order', - field=models.ForeignKey(to='orders.Order', on_delete=models.CASCADE), + model_name="payment", + name="order", + field=models.ForeignKey(to="orders.Order", on_delete=models.CASCADE), ), migrations.AddField( - model_name='payment', - name='polymorphic_ctype', - field=models.ForeignKey(related_name='polymorphic_orders.payment_set+', editable=False, on_delete=models.CASCADE, to='contenttypes.ContentType', null=True), + model_name="payment", + name="polymorphic_ctype", + field=models.ForeignKey( + related_name="polymorphic_orders.payment_set+", + editable=False, + on_delete=models.CASCADE, + to="contenttypes.ContentType", + null=True, + ), ), ] diff --git a/example/orders/models.py b/example/orders/models.py index 8d2b682..cf12286 100644 --- a/example/orders/models.py +++ b/example/orders/models.py @@ -11,12 +11,13 @@ class Order(models.Model): """ An example order that has polymorphic relations """ + title = models.CharField(_("Title"), max_length=200) class Meta: verbose_name = _("Organisation") verbose_name_plural = _("Organisations") - ordering = ('title',) + ordering = ("title",) def __str__(self): return self.title @@ -27,8 +28,9 @@ class Payment(PolymorphicModel): """ A generic payment model. """ + order = models.ForeignKey(Order, on_delete=models.CASCADE) - currency = models.CharField(default='USD', max_length=3) + currency = models.CharField(default="USD", max_length=3) amount = models.DecimalField(max_digits=10, decimal_places=2) class Meta: @@ -43,6 +45,7 @@ class CreditCardPayment(Payment): """ Credit card """ + MONTH_CHOICES = [(i, n) for i, n in sorted(MONTHS_3.items())] card_type = models.CharField(max_length=10) @@ -58,6 +61,7 @@ class BankPayment(Payment): """ Payment by bank """ + bank_name = models.CharField(max_length=100) swift = models.CharField(max_length=20) @@ -70,6 +74,7 @@ class SepaPayment(Payment): """ Payment by SEPA (EU) """ + iban = models.CharField(max_length=34) bic = models.CharField(max_length=11) diff --git a/example/pexp/admin.py b/example/pexp/admin.py index a04ec8b..cc1ca2f 100644 --- a/example/pexp/admin.py +++ b/example/pexp/admin.py @@ -1,6 +1,11 @@ from django.contrib import admin -from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter + from pexp.models import * +from polymorphic.admin import ( + PolymorphicChildModelAdmin, + PolymorphicChildModelFilter, + PolymorphicParentModelAdmin, +) class ProjectAdmin(PolymorphicParentModelAdmin): @@ -14,11 +19,7 @@ class ProjectChildAdmin(PolymorphicChildModelAdmin): # On purpose, only have the shared fields here. # The fields of the derived model should still be displayed. - base_fieldsets = ( - ("Base fields", { - 'fields': ('topic',) - }), - ) + base_fieldsets = (("Base fields", {"fields": ("topic",)}),) admin.site.register(Project, ProjectAdmin) diff --git a/example/pexp/management/commands/p2cmd.py b/example/pexp/management/commands/p2cmd.py index 0f57503..b26026a 100644 --- a/example/pexp/management/commands/p2cmd.py +++ b/example/pexp/management/commands/p2cmd.py @@ -7,12 +7,12 @@ import sys import time from pprint import pprint from random import Random + from django.core.management import BaseCommand from django.db import connection from pexp.models import * - rnd = Random() @@ -24,7 +24,7 @@ def show_queries(): connection.queries = [] -def print_timing(func, message='', iterations=1): +def print_timing(func, message="", iterations=1): def wrapper(*arg): results = [] connection.queries_log.clear() @@ -36,13 +36,12 @@ def print_timing(func, message='', iterations=1): res_sum = 0 for r in results: res_sum += r - print("%s%-19s: %.4f ms, %i queries (%i times)" % ( - message, func.func_name, - res_sum, - len(connection.queries), - iterations - )) + print( + "%s%-19s: %.4f ms, %i queries (%i times)" + % (message, func.func_name, res_sum, len(connection.queries), iterations) + ) sys.stdout.flush() + return wrapper @@ -52,9 +51,9 @@ class Command(BaseCommand): def handle_noargs(self, **options): if False: TestModelA.objects.all().delete() - a = TestModelA.objects.create(field1='A1') - b = TestModelB.objects.create(field1='B1', field2='B2') - c = TestModelC.objects.create(field1='C1', field2='C2', field3='C3') + a = TestModelA.objects.create(field1="A1") + b = TestModelB.objects.create(field1="B1", field2="B2") + c = TestModelC.objects.create(field1="C1", field2="C2", field3="C3") connection.queries_log.clear() print(TestModelC.base_objects.all()) show_queries() @@ -64,7 +63,9 @@ class Command(BaseCommand): for i in range(1000): a = TestModelA.objects.create(field1=str(i % 100)) b = TestModelB.objects.create(field1=str(i % 100), field2=str(i % 200)) - c = TestModelC.objects.create(field1=str(i % 100), field2=str(i % 200), field3=str(i % 300)) + c = TestModelC.objects.create( + field1=str(i % 100), field2=str(i % 200), field3=str(i % 300) + ) if i % 100 == 0: print(i) @@ -77,9 +78,9 @@ class Command(BaseCommand): return NormalModelA.objects.all().delete() - a = NormalModelA.objects.create(field1='A1') - b = NormalModelB.objects.create(field1='B1', field2='B2') - c = NormalModelC.objects.create(field1='C1', field2='C2', field3='C3') + a = NormalModelA.objects.create(field1="A1") + b = NormalModelB.objects.create(field1="B1", field2="B2") + c = NormalModelC.objects.create(field1="C1", field2="C2", field3="C3") qs = TestModelA.objects.raw("SELECT * from pexp_testmodela") for o in list(qs): print(o) @@ -87,7 +88,8 @@ class Command(BaseCommand): def poly_sql_query(): cursor = connection.cursor() - cursor.execute(""" + cursor.execute( + """ SELECT id, pexp_testmodela.field1, pexp_testmodelb.field2, pexp_testmodelc.field3 FROM pexp_testmodela LEFT OUTER JOIN pexp_testmodelb @@ -96,18 +98,23 @@ def poly_sql_query(): ON pexp_testmodelb.testmodela_ptr_id = pexp_testmodelc.testmodelb_ptr_id WHERE pexp_testmodela.field1=%i ORDER BY pexp_testmodela.id - """ % rnd.randint(0, 100)) + """ + % rnd.randint(0, 100) + ) # row=cursor.fetchone() return def poly_sql_query2(): cursor = connection.cursor() - cursor.execute(""" + cursor.execute( + """ SELECT id, pexp_testmodela.field1 FROM pexp_testmodela WHERE pexp_testmodela.field1=%i ORDER BY pexp_testmodela.id - """ % rnd.randint(0, 100)) + """ + % rnd.randint(0, 100) + ) # row=cursor.fetchone() return diff --git a/example/pexp/management/commands/pcmd.py b/example/pexp/management/commands/pcmd.py index 3d4eae7..76cc258 100644 --- a/example/pexp/management/commands/pcmd.py +++ b/example/pexp/management/commands/pcmd.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ This module is a scratchpad for general development, testing & debugging. """ @@ -20,13 +19,15 @@ class Command(NoArgsCommand): Project.objects.all().delete() a = Project.objects.create(topic="John's gathering") b = ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner") - c = ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter") - print Project.objects.all() - print + c = ResearchProject.objects.create( + topic="Swallow Aerodynamics", supervisor="Dr. Winter" + ) + print(Project.objects.all()) + print("") TestModelA.objects.all().delete() - a = TestModelA.objects.create(field1='A1') - b = TestModelB.objects.create(field1='B1', field2='B2') - c = TestModelC.objects.create(field1='C1', field2='C2', field3='C3') - print TestModelA.objects.all() - print + a = TestModelA.objects.create(field1="A1") + b = TestModelB.objects.create(field1="B1", field2="B2") + c = TestModelC.objects.create(field1="C1", field2="C2", field3="C3") + print(TestModelA.objects.all()) + print("") diff --git a/example/pexp/management/commands/polybench.py b/example/pexp/management/commands/polybench.py index 12d44b6..3d1dbe0 100644 --- a/example/pexp/management/commands/polybench.py +++ b/example/pexp/management/commands/polybench.py @@ -3,14 +3,14 @@ This module is a scratchpad for general development, testing & debugging """ -import time import sys +import time +from pprint import pprint from django.core.management import BaseCommand from django.db import connection -from pprint import pprint -from pexp.models import * +from pexp.models import * num_objects = 1000 @@ -27,7 +27,7 @@ def show_queries(): # benchmark wrappers -def print_timing(func, message='', iterations=1): +def print_timing(func, message="", iterations=1): def wrapper(*arg): results = [] connection.queries_log.clear() @@ -40,28 +40,31 @@ def print_timing(func, message='', iterations=1): for r in results: res_sum += r median = res_sum / len(results) - print("%s%-19s: %.0f ms, %i queries" % ( - message, func.func_name, - median, - len(connection.queries) / len(results) - )) + print( + "%s%-19s: %.0f ms, %i queries" + % (message, func.func_name, median, len(connection.queries) / len(results)) + ) sys.stdout.flush() + return wrapper def run_vanilla_any_poly(func, iterations=1): - f = print_timing(func, ' ', iterations) + f = print_timing(func, " ", iterations) f(NormalModelC) - f = print_timing(func, 'poly ', iterations) + f = print_timing(func, "poly ", iterations) f(TestModelC) ################################################################################### # benchmarks + def bench_create(model): for i in range(num_objects): - model.objects.create(field1='abc' + str(i), field2='abcd' + str(i), field3='abcde' + str(i)) + model.objects.create( + field1="abc" + str(i), field2="abcd" + str(i), field3="abcde" + str(i) + ) # print 'count:',model.objects.count() @@ -94,6 +97,7 @@ def bench_load2_short(model): def bench_delete(model): model.objects.all().delete() + ################################################################################### # Command @@ -105,10 +109,10 @@ class Command(BaseCommand): func_list = [ (bench_delete, 1), (bench_create, 1), - (bench_load1, 5), + (bench_load1, 5), (bench_load1_short, 5), (bench_load2, 5), - (bench_load2_short, 5) + (bench_load2_short, 5), ] for f, iterations in func_list: run_vanilla_any_poly(f, iterations=iterations) diff --git a/example/pexp/management/commands/polymorphic_create_test_data.py b/example/pexp/management/commands/polymorphic_create_test_data.py index 761305c..0aa375c 100644 --- a/example/pexp/management/commands/polymorphic_create_test_data.py +++ b/example/pexp/management/commands/polymorphic_create_test_data.py @@ -15,5 +15,7 @@ class Command(BaseCommand): Project.objects.all().delete() o = Project.objects.create(topic="John's gathering") o = ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner") - o = ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter") + o = ResearchProject.objects.create( + topic="Swallow Aerodynamics", supervisor="Dr. Winter" + ) print(Project.objects.all()) diff --git a/example/pexp/migrations/0001_initial.py b/example/pexp/migrations/0001_initial.py index 8157638..7b8ea4d 100644 --- a/example/pexp/migrations/0001_initial.py +++ b/example/pexp/migrations/0001_initial.py @@ -2,181 +2,295 @@ from __future__ import unicode_literals from django.db import migrations, models + import polymorphic.showfields class Migration(migrations.Migration): - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ] + dependencies = [("contenttypes", "0002_remove_content_type_name")] operations = [ migrations.CreateModel( - name='NormalModelA', + name="NormalModelA", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('field1', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("field1", models.CharField(max_length=10)), ], ), migrations.CreateModel( - name='Project', + name="Project", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('topic', models.CharField(max_length=30)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("topic", models.CharField(max_length=30)), ], - options={ - 'abstract': False, - }, + options={"abstract": False}, bases=(polymorphic.showfields.ShowFieldContent, models.Model), ), migrations.CreateModel( - name='ProxyBase', + name="ProxyBase", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('title', models.CharField(max_length=200)), - ('polymorphic_ctype', models.ForeignKey(related_name='polymorphic_pexp.proxybase_set+', editable=False, on_delete=models.CASCADE, to='contenttypes.ContentType', null=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("title", models.CharField(max_length=200)), + ( + "polymorphic_ctype", + models.ForeignKey( + related_name="polymorphic_pexp.proxybase_set+", + editable=False, + on_delete=models.CASCADE, + to="contenttypes.ContentType", + null=True, + ), + ), ], - options={ - 'ordering': ('title',), - }, + options={"ordering": ("title",)}, ), migrations.CreateModel( - name='TestModelA', + name="TestModelA", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('field1', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("field1", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - }, + options={"abstract": False}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='UUIDModelA', + name="UUIDModelA", fields=[ - ('uuid_primary_key', models.UUIDField(serialize=False, primary_key=True)), - ('field1', models.CharField(max_length=10)), + ( + "uuid_primary_key", + models.UUIDField(serialize=False, primary_key=True), + ), + ("field1", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - }, + options={"abstract": False}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='ArtProject', + name="ArtProject", fields=[ - ('project_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, on_delete=models.CASCADE, to='pexp.Project')), - ('artist', models.CharField(max_length=30)), + ( + "project_ptr", + models.OneToOneField( + parent_link=True, + auto_created=True, + primary_key=True, + serialize=False, + on_delete=models.CASCADE, + to="pexp.Project", + ), + ), + ("artist", models.CharField(max_length=30)), ], - options={ - 'abstract': False, - }, - bases=('pexp.project',), + options={"abstract": False}, + bases=("pexp.project",), ), migrations.CreateModel( - name='NormalModelB', + name="NormalModelB", fields=[ - ('normalmodela_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, on_delete=models.CASCADE, to='pexp.NormalModelA')), - ('field2', models.CharField(max_length=10)), + ( + "normalmodela_ptr", + models.OneToOneField( + parent_link=True, + auto_created=True, + primary_key=True, + serialize=False, + on_delete=models.CASCADE, + to="pexp.NormalModelA", + ), + ), + ("field2", models.CharField(max_length=10)), ], - bases=('pexp.normalmodela',), + bases=("pexp.normalmodela",), ), migrations.CreateModel( - name='ResearchProject', + name="ResearchProject", fields=[ - ('project_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, on_delete=models.CASCADE, to='pexp.Project')), - ('supervisor', models.CharField(max_length=30)), + ( + "project_ptr", + models.OneToOneField( + parent_link=True, + auto_created=True, + primary_key=True, + serialize=False, + on_delete=models.CASCADE, + to="pexp.Project", + ), + ), + ("supervisor", models.CharField(max_length=30)), ], - options={ - 'abstract': False, - }, - bases=('pexp.project',), + options={"abstract": False}, + bases=("pexp.project",), ), migrations.CreateModel( - name='TestModelB', + name="TestModelB", fields=[ - ('testmodela_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, on_delete=models.CASCADE, to='pexp.TestModelA')), - ('field2', models.CharField(max_length=10)), + ( + "testmodela_ptr", + models.OneToOneField( + parent_link=True, + auto_created=True, + primary_key=True, + serialize=False, + on_delete=models.CASCADE, + to="pexp.TestModelA", + ), + ), + ("field2", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - }, - bases=('pexp.testmodela',), + options={"abstract": False}, + bases=("pexp.testmodela",), ), migrations.CreateModel( - name='UUIDModelB', + name="UUIDModelB", fields=[ - ('uuidmodela_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, on_delete=models.CASCADE, to='pexp.UUIDModelA')), - ('field2', models.CharField(max_length=10)), + ( + "uuidmodela_ptr", + models.OneToOneField( + parent_link=True, + auto_created=True, + primary_key=True, + serialize=False, + on_delete=models.CASCADE, + to="pexp.UUIDModelA", + ), + ), + ("field2", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - }, - bases=('pexp.uuidmodela',), + options={"abstract": False}, + bases=("pexp.uuidmodela",), ), migrations.AddField( - model_name='uuidmodela', - name='polymorphic_ctype', - field=models.ForeignKey(related_name='polymorphic_pexp.uuidmodela_set+', editable=False, on_delete=models.CASCADE, to='contenttypes.ContentType', null=True), + model_name="uuidmodela", + name="polymorphic_ctype", + field=models.ForeignKey( + related_name="polymorphic_pexp.uuidmodela_set+", + editable=False, + on_delete=models.CASCADE, + to="contenttypes.ContentType", + null=True, + ), ), migrations.AddField( - model_name='testmodela', - name='polymorphic_ctype', - field=models.ForeignKey(related_name='polymorphic_pexp.testmodela_set+', editable=False, on_delete=models.CASCADE, to='contenttypes.ContentType', null=True), + model_name="testmodela", + name="polymorphic_ctype", + field=models.ForeignKey( + related_name="polymorphic_pexp.testmodela_set+", + editable=False, + on_delete=models.CASCADE, + to="contenttypes.ContentType", + null=True, + ), ), migrations.AddField( - model_name='project', - name='polymorphic_ctype', - field=models.ForeignKey(related_name='polymorphic_pexp.project_set+', editable=False, on_delete=models.CASCADE, to='contenttypes.ContentType', null=True), + model_name="project", + name="polymorphic_ctype", + field=models.ForeignKey( + related_name="polymorphic_pexp.project_set+", + editable=False, + on_delete=models.CASCADE, + to="contenttypes.ContentType", + null=True, + ), ), migrations.CreateModel( - name='ProxyA', - fields=[ - ], - options={ - 'proxy': True, - }, - bases=('pexp.proxybase',), + name="ProxyA", fields=[], options={"proxy": True}, bases=("pexp.proxybase",) ), migrations.CreateModel( - name='ProxyB', - fields=[ - ], - options={ - 'proxy': True, - }, - bases=('pexp.proxybase',), + name="ProxyB", fields=[], options={"proxy": True}, bases=("pexp.proxybase",) ), migrations.CreateModel( - name='NormalModelC', + name="NormalModelC", fields=[ - ('normalmodelb_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, on_delete=models.CASCADE, to='pexp.NormalModelB')), - ('field3', models.CharField(max_length=10)), + ( + "normalmodelb_ptr", + models.OneToOneField( + parent_link=True, + auto_created=True, + primary_key=True, + serialize=False, + on_delete=models.CASCADE, + to="pexp.NormalModelB", + ), + ), + ("field3", models.CharField(max_length=10)), ], - bases=('pexp.normalmodelb',), + bases=("pexp.normalmodelb",), ), migrations.CreateModel( - name='TestModelC', + name="TestModelC", fields=[ - ('testmodelb_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, on_delete=models.CASCADE, to='pexp.TestModelB')), - ('field3', models.CharField(max_length=10)), - ('field4', models.ManyToManyField(related_name='related_c', to='pexp.TestModelB')), + ( + "testmodelb_ptr", + models.OneToOneField( + parent_link=True, + auto_created=True, + primary_key=True, + serialize=False, + on_delete=models.CASCADE, + to="pexp.TestModelB", + ), + ), + ("field3", models.CharField(max_length=10)), + ( + "field4", + models.ManyToManyField( + related_name="related_c", to="pexp.TestModelB" + ), + ), ], - options={ - 'abstract': False, - }, - bases=('pexp.testmodelb',), + options={"abstract": False}, + bases=("pexp.testmodelb",), ), migrations.CreateModel( - name='UUIDModelC', + name="UUIDModelC", fields=[ - ('uuidmodelb_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, on_delete=models.CASCADE, to='pexp.UUIDModelB')), - ('field3', models.CharField(max_length=10)), + ( + "uuidmodelb_ptr", + models.OneToOneField( + parent_link=True, + auto_created=True, + primary_key=True, + serialize=False, + on_delete=models.CASCADE, + to="pexp.UUIDModelB", + ), + ), + ("field3", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - }, - bases=('pexp.uuidmodelb',), + options={"abstract": False}, + bases=("pexp.uuidmodelb",), ), ] diff --git a/example/pexp/models.py b/example/pexp/models.py index 26b4768..6e51b9f 100644 --- a/example/pexp/models.py +++ b/example/pexp/models.py @@ -8,6 +8,7 @@ from polymorphic.showfields import ShowFieldContent, ShowFieldTypeAndContent class Project(ShowFieldContent, PolymorphicModel): """Polymorphic model""" + topic = models.CharField(max_length=30) @@ -21,6 +22,7 @@ class ResearchProject(Project): class UUIDModelA(ShowFieldTypeAndContent, PolymorphicModel): """UUID as primary key example""" + uuid_primary_key = models.UUIDField(primary_key=True) field1 = models.CharField(max_length=10) @@ -35,17 +37,17 @@ class UUIDModelC(UUIDModelB): class ProxyBase(PolymorphicModel): """Proxy model example - a single table with multiple types.""" + title = models.CharField(max_length=200) def __unicode__(self): return u"".format(self.polymorphic_ctype, self.title) class Meta: - ordering = ('title',) + ordering = ("title",) class ProxyA(ProxyBase): - class Meta: proxy = True @@ -54,7 +56,6 @@ class ProxyA(ProxyBase): class ProxyB(ProxyBase): - class Meta: proxy = True @@ -64,6 +65,7 @@ class ProxyB(ProxyBase): # Internals for management command tests + class TestModelA(ShowFieldTypeAndContent, PolymorphicModel): field1 = models.CharField(max_length=10) @@ -74,11 +76,12 @@ class TestModelB(TestModelA): class TestModelC(TestModelB): field3 = models.CharField(max_length=10) - field4 = models.ManyToManyField(TestModelB, related_name='related_c') + field4 = models.ManyToManyField(TestModelB, related_name="related_c") class NormalModelA(models.Model): """Normal Django inheritance, no polymorphic behavior""" + field1 = models.CharField(max_length=10) diff --git a/polymorphic/__init__.py b/polymorphic/__init__.py index 07ee3fa..d51f306 100644 --- a/polymorphic/__init__.py +++ b/polymorphic/__init__.py @@ -13,4 +13,3 @@ try: __version__ = pkg_resources.require("django-polymorphic")[0].version except pkg_resources.DistributionNotFound: __version__ = None # for RTD among others - diff --git a/polymorphic/admin/__init__.py b/polymorphic/admin/__init__.py index 5a6efa8..70f810a 100644 --- a/polymorphic/admin/__init__.py +++ b/polymorphic/admin/__init__.py @@ -4,44 +4,38 @@ ModelAdmin code to display polymorphic models. The admin consists of a parent admin (which shows in the admin with a list), and a child admin (which is used internally to show the edit/delete dialog). """ -# Admins for the regular models -from .parentadmin import PolymorphicParentModelAdmin from .childadmin import PolymorphicChildModelAdmin +from .filters import PolymorphicChildModelFilter # Utils from .forms import PolymorphicModelChoiceForm -from .filters import PolymorphicChildModelFilter - -# Inlines -from .inlines import ( - PolymorphicInlineModelAdmin, # base class - StackedPolymorphicInline, # stacked inline -) - -# Helpers for the inlines -from .helpers import ( - PolymorphicInlineAdminForm, - PolymorphicInlineAdminFormSet, - PolymorphicInlineSupportMixin, # mixin for the regular model admin! -) # Expose generic admin features too. There is no need to split those # as the admin already relies on contenttypes. -from .generic import ( - GenericPolymorphicInlineModelAdmin, # base class - GenericStackedPolymorphicInline, # stacked inline -) +from .generic import GenericPolymorphicInlineModelAdmin # base class +from .generic import GenericStackedPolymorphicInline # stacked inline + +# Helpers for the inlines +from .helpers import PolymorphicInlineSupportMixin # mixin for the regular model admin! +from .helpers import PolymorphicInlineAdminForm, PolymorphicInlineAdminFormSet + +# Inlines +from .inlines import PolymorphicInlineModelAdmin # base class +from .inlines import StackedPolymorphicInline # stacked inline + +# Admins for the regular models +from .parentadmin import PolymorphicParentModelAdmin __all__ = ( - 'PolymorphicParentModelAdmin', - 'PolymorphicChildModelAdmin', - 'PolymorphicModelChoiceForm', - 'PolymorphicChildModelFilter', - 'PolymorphicInlineAdminForm', - 'PolymorphicInlineAdminFormSet', - 'PolymorphicInlineSupportMixin', - 'PolymorphicInlineModelAdmin', - 'StackedPolymorphicInline', - 'GenericPolymorphicInlineModelAdmin', - 'GenericStackedPolymorphicInline', + "PolymorphicParentModelAdmin", + "PolymorphicChildModelAdmin", + "PolymorphicModelChoiceForm", + "PolymorphicChildModelFilter", + "PolymorphicInlineAdminForm", + "PolymorphicInlineAdminFormSet", + "PolymorphicInlineSupportMixin", + "PolymorphicInlineModelAdmin", + "StackedPolymorphicInline", + "GenericPolymorphicInlineModelAdmin", + "GenericStackedPolymorphicInline", ) diff --git a/polymorphic/admin/childadmin.py b/polymorphic/admin/childadmin.py index ec5a8ba..cd20773 100644 --- a/polymorphic/admin/childadmin.py +++ b/polymorphic/admin/childadmin.py @@ -8,6 +8,7 @@ from django.urls import resolve from django.utils.translation import ugettext_lazy as _ from polymorphic.utils import get_base_polymorphic_model + from ..admin import PolymorphicParentModelAdmin @@ -46,7 +47,9 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin): show_in_index = False def __init__(self, model, admin_site, *args, **kwargs): - super(PolymorphicChildModelAdmin, self).__init__(model, admin_site, *args, **kwargs) + super(PolymorphicChildModelAdmin, self).__init__( + model, admin_site, *args, **kwargs + ) if self.base_model is None: self.base_model = get_base_polymorphic_model(model) @@ -59,19 +62,23 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin): # # Instead, pass the form unchecked here, because the standard ModelForm will just work. # If the derived class sets the model explicitly, respect that setting. - kwargs.setdefault('form', self.base_form or self.form) + kwargs.setdefault("form", self.base_form or self.form) # prevent infinite recursion when this is called from get_subclass_fields if not self.fieldsets and not self.fields: - kwargs.setdefault('fields', '__all__') + kwargs.setdefault("fields", "__all__") return super(PolymorphicChildModelAdmin, self).get_form(request, obj, **kwargs) def get_model_perms(self, request): match = resolve(request.path) - if not self.show_in_index and match.app_name == 'admin' and match.url_name in ('index', 'app_list'): - return {'add': False, 'change': False, 'delete': False} + if ( + not self.show_in_index + and match.app_name == "admin" + and match.url_name in ("index", "app_list") + ): + return {"add": False, "change": False, "delete": False} return super(PolymorphicChildModelAdmin, self).get_model_perms(request) @property @@ -87,10 +94,11 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin): "admin/%s/%s/change_form.html" % (app_label, opts.object_name.lower()), "admin/%s/change_form.html" % app_label, # Added: - "admin/%s/%s/change_form.html" % (base_app_label, base_opts.object_name.lower()), + "admin/%s/%s/change_form.html" + % (base_app_label, base_opts.object_name.lower()), "admin/%s/change_form.html" % base_app_label, "admin/polymorphic/change_form.html", - "admin/change_form.html" + "admin/change_form.html", ] @property @@ -103,13 +111,15 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin): base_app_label = base_opts.app_label return [ - "admin/%s/%s/delete_confirmation.html" % (app_label, opts.object_name.lower()), + "admin/%s/%s/delete_confirmation.html" + % (app_label, opts.object_name.lower()), "admin/%s/delete_confirmation.html" % app_label, # Added: - "admin/%s/%s/delete_confirmation.html" % (base_app_label, base_opts.object_name.lower()), + "admin/%s/%s/delete_confirmation.html" + % (base_app_label, base_opts.object_name.lower()), "admin/%s/delete_confirmation.html" % base_app_label, "admin/polymorphic/delete_confirmation.html", - "admin/delete_confirmation.html" + "admin/delete_confirmation.html", ] @property @@ -125,15 +135,16 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin): "admin/%s/%s/object_history.html" % (app_label, opts.object_name.lower()), "admin/%s/object_history.html" % app_label, # Added: - "admin/%s/%s/object_history.html" % (base_app_label, base_opts.object_name.lower()), + "admin/%s/%s/object_history.html" + % (base_app_label, base_opts.object_name.lower()), "admin/%s/object_history.html" % base_app_label, "admin/polymorphic/object_history.html", - "admin/object_history.html" + "admin/object_history.html", ] def _get_parent_admin(self): # this returns parent admin instance on which to call response_post_save methods - parent_model = self.model._meta.get_field('polymorphic_ctype').model + parent_model = self.model._meta.get_field("polymorphic_ctype").model if parent_model == self.model: # when parent_model is in among child_models, just return super instance return super(PolymorphicChildModelAdmin, self) @@ -149,11 +160,15 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin): # Fetch admin instance for model class, see if it's a possible candidate. model_admin = self.admin_site._registry.get(klass) - if model_admin is not None and isinstance(model_admin, PolymorphicParentModelAdmin): + if model_admin is not None and isinstance( + model_admin, PolymorphicParentModelAdmin + ): return model_admin # Success! # If we get this far without returning there is no admin available - raise ParentAdminNotRegistered("No parent admin was registered for a '{0}' model.".format(parent_model)) + raise ParentAdminNotRegistered( + "No parent admin was registered for a '{0}' model.".format(parent_model) + ) def response_post_save_add(self, request, obj): return self._get_parent_admin().response_post_save_add(request, obj) @@ -161,26 +176,28 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin): def response_post_save_change(self, request, obj): return self._get_parent_admin().response_post_save_change(request, obj) - def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): - context.update({ - 'base_opts': self.base_model._meta, - }) - return super(PolymorphicChildModelAdmin, self).render_change_form(request, context, add=add, change=change, form_url=form_url, obj=obj) + def render_change_form( + self, request, context, add=False, change=False, form_url="", obj=None + ): + context.update({"base_opts": self.base_model._meta}) + return super(PolymorphicChildModelAdmin, self).render_change_form( + request, context, add=add, change=change, form_url=form_url, obj=obj + ) def delete_view(self, request, object_id, context=None): - extra_context = { - 'base_opts': self.base_model._meta, - } - return super(PolymorphicChildModelAdmin, self).delete_view(request, object_id, extra_context) + extra_context = {"base_opts": self.base_model._meta} + return super(PolymorphicChildModelAdmin, self).delete_view( + request, object_id, extra_context + ) def history_view(self, request, object_id, extra_context=None): # Make sure the history view can also display polymorphic breadcrumbs - context = { - 'base_opts': self.base_model._meta, - } + context = {"base_opts": self.base_model._meta} if extra_context: context.update(extra_context) - return super(PolymorphicChildModelAdmin, self).history_view(request, object_id, extra_context=context) + return super(PolymorphicChildModelAdmin, self).history_view( + request, object_id, extra_context=context + ) # ---- Extra: improving the form/fieldset default display ---- @@ -201,7 +218,7 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin): if other_fields: return ( base_fieldsets[0], - (self.extra_fieldset_title, {'fields': other_fields}), + (self.extra_fieldset_title, {"fields": other_fields}), ) + base_fieldsets[1:] else: return base_fieldsets @@ -215,13 +232,15 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin): # By not declaring the fields/form in the base class, # get_form() will populate the form with all available fields. form = self.get_form(request, obj, exclude=exclude) - subclass_fields = list(form.base_fields.keys()) + list(self.get_readonly_fields(request, obj)) + subclass_fields = list(form.base_fields.keys()) + list( + self.get_readonly_fields(request, obj) + ) # Find which fields are not part of the common fields. for fieldset in self.get_base_fieldsets(request, obj): - for field in fieldset[1]['fields']: + for field in fieldset[1]["fields"]: try: subclass_fields.remove(field) except ValueError: - pass # field not found in form, Django will raise exception later. + pass # field not found in form, Django will raise exception later. return subclass_fields diff --git a/polymorphic/admin/filters.py b/polymorphic/admin/filters.py index 82b4964..171599b 100644 --- a/polymorphic/admin/filters.py +++ b/polymorphic/admin/filters.py @@ -14,11 +14,12 @@ class PolymorphicChildModelFilter(admin.SimpleListFilter): list_filter = (PolymorphicChildModelFilter,) """ - title = _('Type') - parameter_name = 'polymorphic_ctype' + + title = _("Type") + parameter_name = "polymorphic_ctype" def lookups(self, request, model_admin): - return model_admin.get_child_type_choices(request, 'change') + return model_admin.get_child_type_choices(request, "change") def queryset(self, request, queryset): try: @@ -31,5 +32,8 @@ class PolymorphicChildModelFilter(admin.SimpleListFilter): if choice_value == value: return queryset.filter(polymorphic_ctype_id=choice_value) raise PermissionDenied( - 'Invalid ContentType "{0}". It must be registered as child model.'.format(value)) + 'Invalid ContentType "{0}". It must be registered as child model.'.format( + value + ) + ) return queryset diff --git a/polymorphic/admin/forms.py b/polymorphic/admin/forms.py index 8f109c7..08e950f 100644 --- a/polymorphic/admin/forms.py +++ b/polymorphic/admin/forms.py @@ -7,12 +7,15 @@ class PolymorphicModelChoiceForm(forms.Form): """ The default form for the ``add_type_form``. Can be overwritten and replaced. """ - #: Define the label for the radiofield - type_label = _('Type') - ct_id = forms.ChoiceField(label=type_label, widget=AdminRadioSelect(attrs={'class': 'radiolist'})) + #: Define the label for the radiofield + type_label = _("Type") + + ct_id = forms.ChoiceField( + label=type_label, widget=AdminRadioSelect(attrs={"class": "radiolist"}) + ) def __init__(self, *args, **kwargs): # Allow to easily redefine the label (a commonly expected usecase) super(PolymorphicModelChoiceForm, self).__init__(*args, **kwargs) - self.fields['ct_id'].label = self.type_label + self.fields["ct_id"].label = self.type_label diff --git a/polymorphic/admin/generic.py b/polymorphic/admin/generic.py index 91fc082..7981c43 100644 --- a/polymorphic/admin/generic.py +++ b/polymorphic/admin/generic.py @@ -2,14 +2,22 @@ from django.contrib.contenttypes.admin import GenericInlineModelAdmin from django.contrib.contenttypes.models import ContentType from django.utils.functional import cached_property -from polymorphic.formsets import polymorphic_child_forms_factory, BaseGenericPolymorphicInlineFormSet, GenericPolymorphicFormSetChild +from polymorphic.formsets import ( + BaseGenericPolymorphicInlineFormSet, + GenericPolymorphicFormSetChild, + polymorphic_child_forms_factory, +) + from .inlines import PolymorphicInlineModelAdmin -class GenericPolymorphicInlineModelAdmin(PolymorphicInlineModelAdmin, GenericInlineModelAdmin): +class GenericPolymorphicInlineModelAdmin( + PolymorphicInlineModelAdmin, GenericInlineModelAdmin +): """ Base class for variation of inlines based on generic foreign keys. """ + #: The formset class formset = BaseGenericPolymorphicInlineFormSet @@ -31,6 +39,7 @@ class GenericPolymorphicInlineModelAdmin(PolymorphicInlineModelAdmin, GenericInl """ Variation for generic inlines. """ + # Make sure that the GFK fields are excluded from the child forms formset_child = GenericPolymorphicFormSetChild ct_field = "content_type" @@ -42,22 +51,24 @@ class GenericPolymorphicInlineModelAdmin(PolymorphicInlineModelAdmin, GenericInl Expose the ContentType that the child relates to. This can be used for the ``polymorphic_ctype`` field. """ - return ContentType.objects.get_for_model(self.model, for_concrete_model=False) + return ContentType.objects.get_for_model( + self.model, for_concrete_model=False + ) def get_formset_child(self, request, obj=None, **kwargs): # Similar to GenericInlineModelAdmin.get_formset(), # make sure the GFK is automatically excluded from the form - defaults = { - "ct_field": self.ct_field, - "fk_field": self.ct_fk_field, - } + defaults = {"ct_field": self.ct_field, "fk_field": self.ct_fk_field} defaults.update(kwargs) - return super(GenericPolymorphicInlineModelAdmin.Child, self).get_formset_child(request, obj=obj, **defaults) + return super( + GenericPolymorphicInlineModelAdmin.Child, self + ).get_formset_child(request, obj=obj, **defaults) class GenericStackedPolymorphicInline(GenericPolymorphicInlineModelAdmin): """ The stacked layout for generic inlines. """ + #: The default template to use. - template = 'admin/polymorphic/edit_inline/stacked.html' + template = "admin/polymorphic/edit_inline/stacked.html" diff --git a/polymorphic/admin/helpers.py b/polymorphic/admin/helpers.py index f935ed1..d1f6491 100644 --- a/polymorphic/admin/helpers.py +++ b/polymorphic/admin/helpers.py @@ -5,7 +5,7 @@ This makes sure that admin fieldsets/layout settings are exported to the templat """ import json -from django.contrib.admin.helpers import InlineAdminFormSet, InlineAdminForm, AdminField +from django.contrib.admin.helpers import AdminField, InlineAdminForm, InlineAdminFormSet from django.utils.encoding import force_text from django.utils.text import capfirst from django.utils.translation import ugettext @@ -19,11 +19,11 @@ class PolymorphicInlineAdminForm(InlineAdminForm): """ def polymorphic_ctype_field(self): - return AdminField(self.form, 'polymorphic_ctype', False) + return AdminField(self.form, "polymorphic_ctype", False) @property def is_empty(self): - return '__prefix__' in self.form.prefix + return "__prefix__" in self.form.prefix class PolymorphicInlineAdminFormSet(InlineAdminFormSet): @@ -32,15 +32,19 @@ class PolymorphicInlineAdminFormSet(InlineAdminFormSet): """ def __init__(self, *args, **kwargs): - self.request = kwargs.pop('request', None) # Assigned later via PolymorphicInlineSupportMixin later. - self.obj = kwargs.pop('obj', None) + self.request = kwargs.pop( + "request", None + ) # Assigned later via PolymorphicInlineSupportMixin later. + self.obj = kwargs.pop("obj", None) super(PolymorphicInlineAdminFormSet, self).__init__(*args, **kwargs) def __iter__(self): """ Output all forms using the proper subtype settings. """ - for form, original in zip(self.formset.initial_forms, self.formset.get_queryset()): + for form, original in zip( + self.formset.initial_forms, self.formset.get_queryset() + ): # Output the form model = original.get_real_instance_class() child_inline = self.opts.get_child_inline_instance(model) @@ -54,7 +58,7 @@ class PolymorphicInlineAdminFormSet(InlineAdminFormSet): original=original, readonly_fields=self.get_child_readonly_fields(child_inline), model_admin=child_inline, - view_on_site_url=view_on_site_url + view_on_site_url=view_on_site_url, ) # Extra rows, and empty prefixed forms. @@ -88,22 +92,24 @@ class PolymorphicInlineAdminFormSet(InlineAdminFormSet): This overrides the default Django version to add the ``childTypes`` data. """ verbose_name = self.opts.verbose_name - return json.dumps({ - 'name': '#%s' % self.formset.prefix, - 'options': { - 'prefix': self.formset.prefix, - 'addText': ugettext('Add another %(verbose_name)s') % { - 'verbose_name': capfirst(verbose_name), + return json.dumps( + { + "name": "#%s" % self.formset.prefix, + "options": { + "prefix": self.formset.prefix, + "addText": ugettext("Add another %(verbose_name)s") + % {"verbose_name": capfirst(verbose_name)}, + "childTypes": [ + { + "type": model._meta.model_name, + "name": force_text(model._meta.verbose_name), + } + for model in self.formset.child_forms.keys() + ], + "deleteText": ugettext("Remove"), }, - 'childTypes': [ - { - 'type': model._meta.model_name, - 'name': force_text(model._meta.verbose_name) - } for model in self.formset.child_forms.keys() - ], - 'deleteText': ugettext('Remove'), } - }) + ) class PolymorphicInlineSupportMixin(object): @@ -119,14 +125,17 @@ class PolymorphicInlineSupportMixin(object): :class:`~django.contrib.admin.helpers.InlineAdminFormSet` for the polymorphic formsets. """ - def get_inline_formsets(self, request, formsets, inline_instances, obj=None, *args, **kwargs): + def get_inline_formsets( + self, request, formsets, inline_instances, obj=None, *args, **kwargs + ): """ Overwritten version to produce the proper admin wrapping for the polymorphic inline formset. This fixes the media and form appearance of the inline polymorphic models. """ - inline_admin_formsets = super(PolymorphicInlineSupportMixin, self).get_inline_formsets( - request, formsets, inline_instances, obj=obj) + inline_admin_formsets = super( + PolymorphicInlineSupportMixin, self + ).get_inline_formsets(request, formsets, inline_instances, obj=obj) for admin_formset in inline_admin_formsets: if isinstance(admin_formset.formset, BasePolymorphicModelFormSet): diff --git a/polymorphic/admin/inlines.py b/polymorphic/admin/inlines.py index bb25350..6fbc121 100644 --- a/polymorphic/admin/inlines.py +++ b/polymorphic/admin/inlines.py @@ -10,9 +10,14 @@ from django.contrib.admin.utils import flatten_fieldsets from django.core.exceptions import ImproperlyConfigured from django.forms import Media -from polymorphic.formsets import polymorphic_child_forms_factory, BasePolymorphicInlineFormSet, \ - PolymorphicFormSetChild, UnsupportedChildType +from polymorphic.formsets import ( + BasePolymorphicInlineFormSet, + PolymorphicFormSetChild, + UnsupportedChildType, + polymorphic_child_forms_factory, +) from polymorphic.formsets.utils import add_media + from .helpers import PolymorphicInlineSupportMixin @@ -31,14 +36,8 @@ class PolymorphicInlineModelAdmin(InlineModelAdmin): #: The extra media to add for the polymorphic inlines effect. #: This can be redefined for subclasses. polymorphic_media = Media( - js=( - 'polymorphic/js/polymorphic_inlines.js', - ), - css={ - 'all': ( - 'polymorphic/css/polymorphic_inlines.css', - ) - } + js=("polymorphic/js/polymorphic_inlines.js",), + css={"all": ("polymorphic/css/polymorphic_inlines.css",)}, ) #: The extra forms to show @@ -90,7 +89,9 @@ class PolymorphicInlineModelAdmin(InlineModelAdmin): try: return self._child_inlines_lookup[model] except KeyError: - raise UnsupportedChildType("Model '{0}' not found in child_inlines".format(model.__name__)) + raise UnsupportedChildType( + "Model '{0}' not found in child_inlines".format(model.__name__) + ) def get_formset(self, request, obj=None, **kwargs): """ @@ -101,7 +102,9 @@ class PolymorphicInlineModelAdmin(InlineModelAdmin): :rtype: type """ # Construct the FormSet class - FormSet = super(PolymorphicInlineModelAdmin, self).get_formset(request, obj=obj, **kwargs) + FormSet = super(PolymorphicInlineModelAdmin, self).get_formset( + request, obj=obj, **kwargs + ) # Instead of completely redefining super().get_formset(), we use # the regular inlineformset_factory(), and amend that with our extra bits. @@ -151,7 +154,10 @@ class PolymorphicInlineModelAdmin(InlineModelAdmin): child_media = child_instance.media # Avoid adding the same media object again and again - if child_media._css != base_media._css and child_media._js != base_media._js: + if ( + child_media._css != base_media._css + and child_media._js != base_media._js + ): add_media(all_media, child_media) add_media(all_media, self.polymorphic_media) @@ -170,12 +176,15 @@ class PolymorphicInlineModelAdmin(InlineModelAdmin): The model form options however, will all be read. """ + formset_child = PolymorphicFormSetChild extra = 0 # TODO: currently unused for the children. def __init__(self, parent_inline): self.parent_inline = parent_inline - super(PolymorphicInlineModelAdmin.Child, self).__init__(parent_inline.parent_model, parent_inline.admin_site) + super(PolymorphicInlineModelAdmin.Child, self).__init__( + parent_inline.parent_model, parent_inline.admin_site + ) def get_formset(self, request, obj=None, **kwargs): # The child inline is only used to construct the form, @@ -209,8 +218,8 @@ class PolymorphicInlineModelAdmin(InlineModelAdmin): # # Transfer the local inline attributes to the formset child, # this allows overriding settings. - if 'fields' in kwargs: - fields = kwargs.pop('fields') + if "fields" in kwargs: + fields = kwargs.pop("fields") else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) @@ -220,9 +229,15 @@ class PolymorphicInlineModelAdmin(InlineModelAdmin): exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) - exclude.append('polymorphic_ctype') # Django 1.10 blocks it, as it's a readonly field. + exclude.append( + "polymorphic_ctype" + ) # Django 1.10 blocks it, as it's a readonly field. - if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: + if ( + self.exclude is None + and hasattr(self.form, "_meta") + and self.form._meta.exclude + ): # Take the custom ModelForm's Meta.exclude into account only if the # InlineModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) @@ -232,7 +247,9 @@ class PolymorphicInlineModelAdmin(InlineModelAdmin): "form": self.form, "fields": fields, "exclude": exclude or None, - "formfield_callback": partial(self.formfield_for_dbfield, request=request), + "formfield_callback": partial( + self.formfield_for_dbfield, request=request + ), } defaults.update(kwargs) @@ -247,5 +264,6 @@ class StackedPolymorphicInline(PolymorphicInlineModelAdmin): Stacked inline for django-polymorphic models. Since tabular doesn't make much sense with changed fields, just offer this one. """ + #: The default template to use. - template = 'admin/polymorphic/edit_inline/stacked.html' + template = "admin/polymorphic/edit_inline/stacked.html" diff --git a/polymorphic/admin/parentadmin.py b/polymorphic/admin/parentadmin.py index 32fb3a9..986eca8 100644 --- a/polymorphic/admin/parentadmin.py +++ b/polymorphic/admin/parentadmin.py @@ -7,7 +7,7 @@ from django.contrib import admin from django.contrib.admin.helpers import AdminErrorList, AdminForm from django.contrib.admin.templatetags.admin_urls import add_preserved_filters from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import PermissionDenied, ImproperlyConfigured +from django.core.exceptions import ImproperlyConfigured, PermissionDenied from django.db import models from django.http import Http404, HttpResponseRedirect from django.template.response import TemplateResponse @@ -15,9 +15,10 @@ from django.utils.encoding import force_text from django.utils.http import urlencode from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ -from polymorphic.utils import get_base_polymorphic_model -from .forms import PolymorphicModelChoiceForm +from polymorphic.utils import get_base_polymorphic_model + +from .forms import PolymorphicModelChoiceForm try: # Django 2.0+ @@ -73,7 +74,9 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): pk_regex = r"(\d+|__fk__)" def __init__(self, model, admin_site, *args, **kwargs): - super(PolymorphicParentModelAdmin, self).__init__(model, admin_site, *args, **kwargs) + super(PolymorphicParentModelAdmin, self).__init__( + model, admin_site, *args, **kwargs + ) self._is_setup = False if self.base_model is None: @@ -105,12 +108,22 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): # After the get_urls() is called, the URLs of the child model can't be exposed anymore to the Django URLconf, # which also means that a "Save and continue editing" button won't work. if self._is_setup: - raise RegistrationClosed("The admin model can't be registered anymore at this point.") + raise RegistrationClosed( + "The admin model can't be registered anymore at this point." + ) if not issubclass(model, self.base_model): - raise TypeError("{0} should be a subclass of {1}".format(model.__name__, self.base_model.__name__)) + raise TypeError( + "{0} should be a subclass of {1}".format( + model.__name__, self.base_model.__name__ + ) + ) if not issubclass(model_admin, admin.ModelAdmin): - raise TypeError("{0} should be a subclass of {1}".format(model_admin.__name__, admin.ModelAdmin.__name__)) + raise TypeError( + "{0} should be a subclass of {1}".format( + model_admin.__name__, admin.ModelAdmin.__name__ + ) + ) self._child_admin_site.register(model, model_admin) @@ -134,7 +147,7 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): self._lazy_setup() choices = [] for model in self.get_child_models(): - perm_function_name = 'has_{0}_permission'.format(action) + perm_function_name = "has_{0}_permission".format(action) model_admin = self._get_real_admin_by_model(model) perm_function = getattr(model_admin, perm_function_name) if not perm_function(request): @@ -145,21 +158,28 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): def _get_real_admin(self, object_id, super_if_self=True): try: - obj = self.model.objects.non_polymorphic() \ - .values('polymorphic_ctype').get(pk=object_id) + obj = ( + self.model.objects.non_polymorphic() + .values("polymorphic_ctype") + .get(pk=object_id) + ) except self.model.DoesNotExist: raise Http404 - return self._get_real_admin_by_ct(obj['polymorphic_ctype'], super_if_self=super_if_self) + return self._get_real_admin_by_ct( + obj["polymorphic_ctype"], super_if_self=super_if_self + ) def _get_real_admin_by_ct(self, ct_id, super_if_self=True): try: ct = ContentType.objects.get_for_id(ct_id) except ContentType.DoesNotExist as e: - raise Http404(e) # Handle invalid GET parameters + raise Http404(e) # Handle invalid GET parameters model_class = ct.model_class() if not model_class: - raise Http404("No model found for '{0}.{1}'.".format(*ct.natural_key())) # Handle model deletion + raise Http404( + "No model found for '{0}.{1}'.".format(*ct.natural_key()) + ) # Handle model deletion return self._get_real_admin_by_model(model_class, super_if_self=super_if_self) @@ -167,14 +187,22 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): # In case of a ?ct_id=### parameter, the view is already checked for permissions. # Hence, make sure this is a derived object, or risk exposing other admin interfaces. if model_class not in self._child_models: - raise PermissionDenied("Invalid model '{0}', it must be registered as child model.".format(model_class)) + raise PermissionDenied( + "Invalid model '{0}', it must be registered as child model.".format( + model_class + ) + ) try: # HACK: the only way to get the instance of an model admin, # is to read the registry of the AdminSite. real_admin = self._child_admin_site._registry[model_class] except KeyError: - raise ChildAdminNotRegistered("No child admin site was registered for a '{0}' model.".format(model_class)) + raise ChildAdminNotRegistered( + "No child admin site was registered for a '{0}' model.".format( + model_class + ) + ) if super_if_self and real_admin is self: return super(PolymorphicParentModelAdmin, self) @@ -188,19 +216,21 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): qs = qs.non_polymorphic() return qs - def add_view(self, request, form_url='', extra_context=None): + def add_view(self, request, form_url="", extra_context=None): """Redirect the add view to the real admin.""" - ct_id = int(request.GET.get('ct_id', 0)) + ct_id = int(request.GET.get("ct_id", 0)) if not ct_id: # Display choices return self.add_type_view(request) else: real_admin = self._get_real_admin_by_ct(ct_id) # rebuild form_url, otherwise libraries below will override it. - form_url = add_preserved_filters({ - 'preserved_filters': urlencode({'ct_id': ct_id}), - 'opts': self.model._meta}, - form_url + form_url = add_preserved_filters( + { + "preserved_filters": urlencode({"ct_id": ct_id}), + "opts": self.model._meta, + }, + form_url, ) return real_admin.add_view(request, form_url, extra_context) @@ -218,7 +248,9 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): return real_admin.changeform_view(request, object_id, *args, **kwargs) else: # Add view. As it should already be handled via `add_view`, this means something custom is done here! - return super(PolymorphicParentModelAdmin, self).changeform_view(request, object_id, *args, **kwargs) + return super(PolymorphicParentModelAdmin, self).changeform_view( + request, object_id, *args, **kwargs + ) def history_view(self, request, object_id, extra_context=None): """Redirect the history view to the real admin.""" @@ -231,14 +263,14 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): return real_admin.delete_view(request, object_id, extra_context) def get_preserved_filters(self, request): - if '_changelist_filters' in request.GET: + if "_changelist_filters" in request.GET: request.GET = request.GET.copy() - filters = request.GET.get('_changelist_filters') + filters = request.GET.get("_changelist_filters") f = filters.split("&") for x in f: - c = x.split('=') + c = x.split("=") request.GET[c[0]] = c[1] - del request.GET['_changelist_filters'] + del request.GET["_changelist_filters"] return super(PolymorphicParentModelAdmin, self).get_preserved_filters(request) def get_urls(self): @@ -256,91 +288,100 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): """ Forward any request to a custom view of the real admin. """ - ct_id = int(request.GET.get('ct_id', 0)) + ct_id = int(request.GET.get("ct_id", 0)) if not ct_id: # See if the path started with an ID. try: - pos = path.find('/') + pos = path.find("/") if pos == -1: object_id = long(path) else: object_id = long(path[0:pos]) except ValueError: - raise Http404("No ct_id parameter, unable to find admin subclass for path '{0}'.".format(path)) + raise Http404( + "No ct_id parameter, unable to find admin subclass for path '{0}'.".format( + path + ) + ) - ct_id = self.model.objects.values_list('polymorphic_ctype_id', flat=True).get(pk=object_id) + ct_id = self.model.objects.values_list( + "polymorphic_ctype_id", flat=True + ).get(pk=object_id) real_admin = self._get_real_admin_by_ct(ct_id) - resolver = URLResolver('^', real_admin.urls) + resolver = URLResolver("^", real_admin.urls) resolvermatch = resolver.resolve(path) # May raise Resolver404 if not resolvermatch: raise Http404("No match for path '{0}' in admin subclass.".format(path)) return resolvermatch.func(request, *resolvermatch.args, **resolvermatch.kwargs) - def add_type_view(self, request, form_url=''): + def add_type_view(self, request, form_url=""): """ Display a choice form to select which page type to add. """ if not self.has_add_permission(request): raise PermissionDenied - extra_qs = '' - if request.META['QUERY_STRING']: + extra_qs = "" + if request.META["QUERY_STRING"]: # QUERY_STRING is bytes in Python 3, using force_text() to decode it as string. # See QueryDict how Django deals with that. - extra_qs = '&{0}'.format(force_text(request.META['QUERY_STRING'])) + extra_qs = "&{0}".format(force_text(request.META["QUERY_STRING"])) - choices = self.get_child_type_choices(request, 'add') + choices = self.get_child_type_choices(request, "add") if len(choices) == 1: - return HttpResponseRedirect('?ct_id={0}{1}'.format(choices[0][0], extra_qs)) + return HttpResponseRedirect("?ct_id={0}{1}".format(choices[0][0], extra_qs)) # Create form form = self.add_type_form( - data=request.POST if request.method == 'POST' else None, - initial={'ct_id': choices[0][0]} + data=request.POST if request.method == "POST" else None, + initial={"ct_id": choices[0][0]}, ) - form.fields['ct_id'].choices = choices + form.fields["ct_id"].choices = choices if form.is_valid(): - return HttpResponseRedirect('?ct_id={0}{1}'.format(form.cleaned_data['ct_id'], extra_qs)) + return HttpResponseRedirect( + "?ct_id={0}{1}".format(form.cleaned_data["ct_id"], extra_qs) + ) # Wrap in all admin layout - fieldsets = ((None, {'fields': ('ct_id',)}),) + fieldsets = ((None, {"fields": ("ct_id",)}),) adminForm = AdminForm(form, fieldsets, {}, model_admin=self) media = self.media + adminForm.media opts = self.model._meta context = { - 'title': _('Add %s') % force_text(opts.verbose_name), - 'adminform': adminForm, - 'is_popup': ("_popup" in request.POST or - "_popup" in request.GET), - 'media': mark_safe(media), - 'errors': AdminErrorList(form, ()), - 'app_label': opts.app_label, + "title": _("Add %s") % force_text(opts.verbose_name), + "adminform": adminForm, + "is_popup": ("_popup" in request.POST or "_popup" in request.GET), + "media": mark_safe(media), + "errors": AdminErrorList(form, ()), + "app_label": opts.app_label, } return self.render_add_type_form(request, context, form_url) - def render_add_type_form(self, request, context, form_url=''): + def render_add_type_form(self, request, context, form_url=""): """ Render the page type choice form. """ opts = self.model._meta app_label = opts.app_label - context.update({ - 'has_change_permission': self.has_change_permission(request), - 'form_url': mark_safe(form_url), - 'opts': opts, - 'add': True, - 'save_on_top': self.save_on_top, - }) + context.update( + { + "has_change_permission": self.has_change_permission(request), + "form_url": mark_safe(form_url), + "opts": opts, + "add": True, + "save_on_top": self.save_on_top, + } + ) templates = self.add_type_template or [ "admin/%s/%s/add_type_form.html" % (app_label, opts.object_name.lower()), "admin/%s/add_type_form.html" % app_label, "admin/polymorphic/add_type_form.html", # added default here - "admin/add_type_form.html" + "admin/add_type_form.html", ] request.current_app = self.admin_site.name @@ -359,7 +400,8 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin): "admin/%s/%s/change_list.html" % (app_label, opts.object_name.lower()), "admin/%s/change_list.html" % app_label, # Added base class: - "admin/%s/%s/change_list.html" % (base_app_label, base_opts.object_name.lower()), + "admin/%s/%s/change_list.html" + % (base_app_label, base_opts.object_name.lower()), "admin/%s/change_list.html" % base_app_label, - "admin/change_list.html" + "admin/change_list.html", ] diff --git a/polymorphic/base.py b/polymorphic/base.py index ed60679..81d988a 100644 --- a/polymorphic/base.py +++ b/polymorphic/base.py @@ -20,9 +20,11 @@ from .query import PolymorphicQuerySet # PolymorphicQuerySet Q objects (and filter()) support these additional key words. # These are forbidden as field names (a descriptive exception is raised) -POLYMORPHIC_SPECIAL_Q_KWORDS = ['instance_of', 'not_instance_of'] +POLYMORPHIC_SPECIAL_Q_KWORDS = ["instance_of", "not_instance_of"] -DUMPDATA_COMMAND = os.path.join('django', 'core', 'management', 'commands', 'dumpdata.py') +DUMPDATA_COMMAND = os.path.join( + "django", "core", "management", "commands", "dumpdata.py" +) class ManagerInheritanceWarning(RuntimeWarning): @@ -32,6 +34,7 @@ class ManagerInheritanceWarning(RuntimeWarning): ################################################################################### # PolymorphicModel meta class + class PolymorphicModelBase(ModelBase): """ Manager inheritance is a pretty complex topic which may need @@ -60,17 +63,21 @@ class PolymorphicModelBase(ModelBase): # print; print '###', model_name, '- bases:', bases # Workaround compatibility issue with six.with_metaclass() and custom Django model metaclasses: - if not attrs and model_name == 'NewBase': - return super(PolymorphicModelBase, self).__new__(self, model_name, bases, attrs) + if not attrs and model_name == "NewBase": + return super(PolymorphicModelBase, self).__new__( + self, model_name, bases, attrs + ) # Make sure that manager_inheritance_from_future is set, since django-polymorphic 1.x already # simulated that behavior on the polymorphic manager to all subclasses behave like polymorphics if django.VERSION < (2, 0): - if 'Meta' in attrs: - if not hasattr(attrs['Meta'], 'manager_inheritance_from_future'): - attrs['Meta'].manager_inheritance_from_future = True + if "Meta" in attrs: + if not hasattr(attrs["Meta"], "manager_inheritance_from_future"): + attrs["Meta"].manager_inheritance_from_future = True else: - attrs['Meta'] = type('Meta', (object,), {'manager_inheritance_from_future': True}) + attrs["Meta"] = type( + "Meta", (object,), {"manager_inheritance_from_future": True} + ) # create new model new_class = self.call_superclass_new_method(model_name, bases, attrs) @@ -103,17 +110,21 @@ class PolymorphicModelBase(ModelBase): # We run into this problem if polymorphic.py is located in a top-level directory # which is directly in the python path. To work around this we temporarily set # app_label here for PolymorphicModel. - meta = attrs.get('Meta', None) - do_app_label_workaround = (meta - and attrs['__module__'] == 'polymorphic' - and model_name == 'PolymorphicModel' - and getattr(meta, 'app_label', None) is None) + meta = attrs.get("Meta", None) + do_app_label_workaround = ( + meta + and attrs["__module__"] == "polymorphic" + and model_name == "PolymorphicModel" + and getattr(meta, "app_label", None) is None + ) if do_app_label_workaround: - meta.app_label = 'poly_dummy_app_label' - new_class = super(PolymorphicModelBase, self).__new__(self, model_name, bases, attrs) + meta.app_label = "poly_dummy_app_label" + new_class = super(PolymorphicModelBase, self).__new__( + self, model_name, bases, attrs + ) if do_app_label_workaround: - del(meta.app_label) + del meta.app_label return new_class @classmethod @@ -133,17 +144,25 @@ class PolymorphicModelBase(ModelBase): if django.VERSION < (2, 0): extra = "\nConsider using Meta.manager_inheritance_from_future = True for Django 1.x projects" else: - extra = '' - e = ('PolymorphicModel: "{0}.{1}" manager is of type "{2}", but must be a subclass of' - ' PolymorphicManager.{extra} to support retrieving subclasses'.format( - model_name, manager_name, type(manager).__name__, extra=extra)) + extra = "" + e = ( + 'PolymorphicModel: "{0}.{1}" manager is of type "{2}", but must be a subclass of' + " PolymorphicManager.{extra} to support retrieving subclasses".format( + model_name, manager_name, type(manager).__name__, extra=extra + ) + ) warnings.warn(e, ManagerInheritanceWarning, stacklevel=3) return manager - if not getattr(manager, 'queryset_class', None) or not issubclass(manager.queryset_class, PolymorphicQuerySet): - e = ('PolymorphicModel: "{0}.{1}" has been instantiated with a queryset class ' - 'which is not a subclass of PolymorphicQuerySet (which is required)'.format( - model_name, manager_name)) + if not getattr(manager, "queryset_class", None) or not issubclass( + manager.queryset_class, PolymorphicQuerySet + ): + e = ( + 'PolymorphicModel: "{0}.{1}" has been instantiated with a queryset class ' + "which is not a subclass of PolymorphicQuerySet (which is required)".format( + model_name, manager_name + ) + ) warnings.warn(e, ManagerInheritanceWarning, stacklevel=3) return manager @@ -151,8 +170,12 @@ class PolymorphicModelBase(ModelBase): def base_objects(self): warnings.warn( "Using PolymorphicModel.base_objects is deprecated.\n" - "Use {0}.objects.non_polymorphic() instead.".format(self.__class__.__name__), - DeprecationWarning, stacklevel=2) + "Use {0}.objects.non_polymorphic() instead.".format( + self.__class__.__name__ + ), + DeprecationWarning, + stacklevel=2, + ) return self._base_objects @property @@ -162,13 +185,13 @@ class PolymorphicModelBase(ModelBase): # manager as default manager for the third level of inheritance when # that third level doesn't define a manager at all. manager = models.Manager() - manager.name = 'base_objects' + manager.name = "base_objects" manager.model = self return manager @property def _default_manager(self): - if len(sys.argv) > 1 and sys.argv[1] == 'dumpdata': + if len(sys.argv) > 1 and sys.argv[1] == "dumpdata": # TODO: investigate Django how this can be avoided # hack: a small patch to Django would be a better solution. # Django's management command 'dumpdata' relies on non-polymorphic @@ -178,14 +201,19 @@ class PolymorphicModelBase(ModelBase): # (non-polymorphic default manager is 'base_objects' for polymorphic models). # This way we don't need to patch django.core.management.commands.dumpdata # for all supported Django versions. - frm = inspect.stack()[1] # frm[1] is caller file name, frm[3] is caller function name + frm = inspect.stack()[ + 1 + ] # frm[1] is caller file name, frm[3] is caller function name if DUMPDATA_COMMAND in frm[1]: return self._base_objects manager = super(PolymorphicModelBase, self)._default_manager if not isinstance(manager, PolymorphicManager): - warnings.warn("{0}._default_manager is not a PolymorphicManager".format( - self.__class__.__name__ - ), ManagerInheritanceWarning) + warnings.warn( + "{0}._default_manager is not a PolymorphicManager".format( + self.__class__.__name__ + ), + ManagerInheritanceWarning, + ) return manager diff --git a/polymorphic/compat.py b/polymorphic/compat.py index ede0d5e..e52a3a9 100644 --- a/polymorphic/compat.py +++ b/polymorphic/compat.py @@ -1,21 +1,20 @@ """Compatibility with Python 2 (taken from 'django.utils.six')""" import sys - PY2 = sys.version_info[0] == 2 PY3 = sys.version_info[0] == 3 if PY3: - string_types = str, - integer_types = int, - class_types = type, + string_types = (str,) + integer_types = (int,) + class_types = (type,) text_type = str binary_type = bytes MAXSIZE = sys.maxsize else: - string_types = basestring, + string_types = (basestring,) integer_types = (int, long) @@ -23,7 +22,8 @@ def with_metaclass(meta, *bases): class metaclass(type): def __new__(cls, name, this_bases, d): return meta(name, bases, d) - return type.__new__(metaclass, 'temporary_class', (), {}) + + return type.__new__(metaclass, "temporary_class", (), {}) def python_2_unicode_compatible(klass): @@ -35,10 +35,11 @@ def python_2_unicode_compatible(klass): returning text and apply this decorator to the class. """ if PY2: - if '__str__' not in klass.__dict__: - raise ValueError("@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % - klass.__name__) + if "__str__" not in klass.__dict__: + raise ValueError( + "@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % klass.__name__ + ) klass.__unicode__ = klass.__str__ - klass.__str__ = lambda self: self.__unicode__().encode('utf-8') + klass.__str__ = lambda self: self.__unicode__().encode("utf-8") return klass diff --git a/polymorphic/contrib/extra_views.py b/polymorphic/contrib/extra_views.py index 50e9189..f3e050d 100644 --- a/polymorphic/contrib/extra_views.py +++ b/polymorphic/contrib/extra_views.py @@ -5,15 +5,20 @@ The ``extra_views.advanced`` provides a method to combine that with a create/upd This package provides classes that support both options for polymorphic formsets. """ from __future__ import absolute_import -from django.core.exceptions import ImproperlyConfigured -import extra_views -from polymorphic.formsets import polymorphic_child_forms_factory, BasePolymorphicModelFormSet, BasePolymorphicInlineFormSet +import extra_views +from django.core.exceptions import ImproperlyConfigured + +from polymorphic.formsets import ( + BasePolymorphicInlineFormSet, + BasePolymorphicModelFormSet, + polymorphic_child_forms_factory, +) __all__ = ( - 'PolymorphicFormSetView', - 'PolymorphicInlineFormSetView', - 'PolymorphicInlineFormSet', + "PolymorphicFormSetView", + "PolymorphicInlineFormSetView", + "PolymorphicInlineFormSet", ) @@ -25,7 +30,7 @@ class PolymorphicFormSetMixin(object): formset_class = BasePolymorphicModelFormSet #: Default 0 extra forms - factory_kwargs = {'extra': 0} + factory_kwargs = {"extra": 0} #: Define the children # :type: list[PolymorphicFormSetChild] @@ -36,7 +41,9 @@ class PolymorphicFormSetMixin(object): :rtype: list[PolymorphicFormSetChild] """ if not self.formset_children: - raise ImproperlyConfigured("Define 'formset_children' as list of `PolymorphicFormSetChild`") + raise ImproperlyConfigured( + "Define 'formset_children' as list of `PolymorphicFormSetChild`" + ) return self.formset_children def get_formset_child_kwargs(self): @@ -51,7 +58,9 @@ class PolymorphicFormSetMixin(object): # reuse the standard factories, and then add `child_forms`, the same can be done here. # This makes sure the base class construction is completely honored. FormSet = super(PolymorphicFormSetMixin, self).get_formset() - FormSet.child_forms = polymorphic_child_forms_factory(self.get_formset_children(), **self.get_formset_child_kwargs()) + FormSet.child_forms = polymorphic_child_forms_factory( + self.get_formset_children(), **self.get_formset_child_kwargs() + ) return FormSet @@ -72,10 +81,13 @@ class PolymorphicFormSetView(PolymorphicFormSetMixin, extra_views.ModelFormSetVi ] """ + formset_class = BasePolymorphicModelFormSet -class PolymorphicInlineFormSetView(PolymorphicFormSetMixin, extra_views.InlineFormSetView): +class PolymorphicInlineFormSetView( + PolymorphicFormSetMixin, extra_views.InlineFormSetView +): """ A view that displays a single polymorphic formset - with one parent object. This is a variation of the :mod:`extra_views` package classes for django-polymorphic. @@ -93,10 +105,13 @@ class PolymorphicInlineFormSetView(PolymorphicFormSetMixin, extra_views.InlineFo PolymorphicFormSetChild(ItemSubclass2), ] """ + formset_class = BasePolymorphicInlineFormSet -class PolymorphicInlineFormSet(PolymorphicFormSetMixin, extra_views.InlineFormSetFactory): +class PolymorphicInlineFormSet( + PolymorphicFormSetMixin, extra_views.InlineFormSetFactory +): """ An inline to add to the ``inlines`` of the :class:`~extra_views.advanced.CreateWithInlinesView` @@ -123,4 +138,5 @@ class PolymorphicInlineFormSet(PolymorphicFormSetMixin, extra_views.InlineFormSe return self.object.get_absolute_url() """ + formset_class = BasePolymorphicInlineFormSet diff --git a/polymorphic/contrib/guardian.py b/polymorphic/contrib/guardian.py index 55b1601..a22ed96 100644 --- a/polymorphic/contrib/guardian.py +++ b/polymorphic/contrib/guardian.py @@ -10,7 +10,7 @@ def get_polymorphic_base_content_type(obj): https://django-guardian.readthedocs.io/en/latest/configuration.html#guardian-get-content-type """ - if hasattr(obj, 'polymorphic_model_marker'): + if hasattr(obj, "polymorphic_model_marker"): try: superclasses = list(obj.__class__.mro()) except TypeError: @@ -19,11 +19,11 @@ def get_polymorphic_base_content_type(obj): polymorphic_superclasses = list() for sclass in superclasses: - if hasattr(sclass, 'polymorphic_model_marker'): + if hasattr(sclass, "polymorphic_model_marker"): polymorphic_superclasses.append(sclass) # PolymorphicMPTT adds an additional class between polymorphic and base class. - if hasattr(obj, 'can_have_children'): + if hasattr(obj, "can_have_children"): root_polymorphic_class = polymorphic_superclasses[-3] else: root_polymorphic_class = polymorphic_superclasses[-2] diff --git a/polymorphic/formsets/__init__.py b/polymorphic/formsets/__init__.py index 1f3b335..d0229c3 100644 --- a/polymorphic/formsets/__init__.py +++ b/polymorphic/formsets/__init__.py @@ -8,31 +8,30 @@ For every child type, there is an :class:`PolymorphicFormSetChild` instance that describes how to display and construct the child. It's parameters are very similar to the parent's factory method. """ -from .models import ( - BasePolymorphicModelFormSet, - BasePolymorphicInlineFormSet, - PolymorphicFormSetChild, - UnsupportedChildType, - polymorphic_modelformset_factory, - polymorphic_inlineformset_factory, - polymorphic_child_forms_factory, -) -from .generic import ( - # Can import generic here, as polymorphic already depends on the 'contenttypes' app. +from .generic import ( # Can import generic here, as polymorphic already depends on the 'contenttypes' app. BaseGenericPolymorphicInlineFormSet, GenericPolymorphicFormSetChild, generic_polymorphic_inlineformset_factory, ) +from .models import ( + BasePolymorphicInlineFormSet, + BasePolymorphicModelFormSet, + PolymorphicFormSetChild, + UnsupportedChildType, + polymorphic_child_forms_factory, + polymorphic_inlineformset_factory, + polymorphic_modelformset_factory, +) __all__ = ( - 'BasePolymorphicModelFormSet', - 'BasePolymorphicInlineFormSet', - 'PolymorphicFormSetChild', - 'UnsupportedChildType', - 'polymorphic_modelformset_factory', - 'polymorphic_inlineformset_factory', - 'polymorphic_child_forms_factory', - 'BaseGenericPolymorphicInlineFormSet', - 'GenericPolymorphicFormSetChild', - 'generic_polymorphic_inlineformset_factory', + "BasePolymorphicModelFormSet", + "BasePolymorphicInlineFormSet", + "PolymorphicFormSetChild", + "UnsupportedChildType", + "polymorphic_modelformset_factory", + "polymorphic_inlineformset_factory", + "polymorphic_child_forms_factory", + "BaseGenericPolymorphicInlineFormSet", + "GenericPolymorphicFormSetChild", + "generic_polymorphic_inlineformset_factory", ) diff --git a/polymorphic/formsets/generic.py b/polymorphic/formsets/generic.py index 610fb25..cf8fac5 100644 --- a/polymorphic/formsets/generic.py +++ b/polymorphic/formsets/generic.py @@ -1,9 +1,16 @@ -from django.contrib.contenttypes.forms import BaseGenericInlineFormSet, generic_inlineformset_factory +from django.contrib.contenttypes.forms import ( + BaseGenericInlineFormSet, + generic_inlineformset_factory, +) from django.contrib.contenttypes.models import ContentType from django.db import models from django.forms.models import ModelForm -from .models import BasePolymorphicModelFormSet, polymorphic_child_forms_factory, PolymorphicFormSetChild +from .models import ( + BasePolymorphicModelFormSet, + PolymorphicFormSetChild, + polymorphic_child_forms_factory, +) class GenericPolymorphicFormSetChild(PolymorphicFormSetChild): @@ -12,8 +19,8 @@ class GenericPolymorphicFormSetChild(PolymorphicFormSetChild): """ def __init__(self, *args, **kwargs): - self.ct_field = kwargs.pop('ct_field', 'content_type') - self.fk_field = kwargs.pop('fk_field', 'object_id') + self.ct_field = kwargs.pop("ct_field", "content_type") + self.fk_field = kwargs.pop("fk_field", "object_id") super(GenericPolymorphicFormSetChild, self).__init__(*args, **kwargs) def get_form(self, ct_field="content_type", fk_field="object_id", **kwargs): @@ -21,7 +28,7 @@ class GenericPolymorphicFormSetChild(PolymorphicFormSetChild): Construct the form class for the formset child. """ exclude = list(self.exclude) - extra_exclude = kwargs.pop('extra_exclude', None) + extra_exclude = kwargs.pop("extra_exclude", None) if extra_exclude: exclude += list(extra_exclude) @@ -31,33 +38,52 @@ class GenericPolymorphicFormSetChild(PolymorphicFormSetChild): opts = self.model._meta ct_field = opts.get_field(self.ct_field) - if not isinstance(ct_field, models.ForeignKey) or ct_field.remote_field.model != ContentType: - raise Exception("fk_name '%s' is not a ForeignKey to ContentType" % ct_field) + if ( + not isinstance(ct_field, models.ForeignKey) + or ct_field.remote_field.model != ContentType + ): + raise Exception( + "fk_name '%s' is not a ForeignKey to ContentType" % ct_field + ) fk_field = opts.get_field(self.fk_field) # let the exception propagate exclude.extend([ct_field.name, fk_field.name]) - kwargs['exclude'] = exclude + kwargs["exclude"] = exclude return super(GenericPolymorphicFormSetChild, self).get_form(**kwargs) -class BaseGenericPolymorphicInlineFormSet(BaseGenericInlineFormSet, BasePolymorphicModelFormSet): +class BaseGenericPolymorphicInlineFormSet( + BaseGenericInlineFormSet, BasePolymorphicModelFormSet +): """ Polymorphic formset variation for inline generic formsets """ -def generic_polymorphic_inlineformset_factory(model, formset_children, form=ModelForm, - formset=BaseGenericPolymorphicInlineFormSet, - ct_field="content_type", fk_field="object_id", - # Base form - # TODO: should these fields be removed in favor of creating - # the base form as a formset child too? - fields=None, exclude=None, - extra=1, can_order=False, can_delete=True, - max_num=None, formfield_callback=None, - validate_max=False, for_concrete_model=True, - min_num=None, validate_min=False, child_form_kwargs=None): +def generic_polymorphic_inlineformset_factory( + model, + formset_children, + form=ModelForm, + formset=BaseGenericPolymorphicInlineFormSet, + ct_field="content_type", + fk_field="object_id", + # Base form + # TODO: should these fields be removed in favor of creating + # the base form as a formset child too? + fields=None, + exclude=None, + extra=1, + can_order=False, + can_delete=True, + max_num=None, + formfield_callback=None, + validate_max=False, + for_concrete_model=True, + min_num=None, + validate_min=False, + child_form_kwargs=None, +): """ Construct the class for a generic inline polymorphic formset. @@ -70,22 +96,22 @@ def generic_polymorphic_inlineformset_factory(model, formset_children, form=Mode :rtype: type """ kwargs = { - 'model': model, - 'form': form, - 'formfield_callback': formfield_callback, - 'formset': formset, - 'ct_field': ct_field, - 'fk_field': fk_field, - 'extra': extra, - 'can_delete': can_delete, - 'can_order': can_order, - 'fields': fields, - 'exclude': exclude, - 'min_num': min_num, - 'max_num': max_num, - 'validate_min': validate_min, - 'validate_max': validate_max, - 'for_concrete_model': for_concrete_model, + "model": model, + "form": form, + "formfield_callback": formfield_callback, + "formset": formset, + "ct_field": ct_field, + "fk_field": fk_field, + "extra": extra, + "can_delete": can_delete, + "can_order": can_order, + "fields": fields, + "exclude": exclude, + "min_num": min_num, + "max_num": max_num, + "validate_min": validate_min, + "validate_max": validate_max, + "for_concrete_model": for_concrete_model, # 'localized_fields': localized_fields, # 'labels': labels, # 'help_texts': help_texts, @@ -97,12 +123,14 @@ def generic_polymorphic_inlineformset_factory(model, formset_children, form=Mode child_kwargs = { # 'exclude': exclude, - 'ct_field': ct_field, - 'fk_field': fk_field, + "ct_field": ct_field, + "fk_field": fk_field, } if child_form_kwargs: child_kwargs.update(child_form_kwargs) FormSet = generic_inlineformset_factory(**kwargs) - FormSet.child_forms = polymorphic_child_forms_factory(formset_children, **child_kwargs) + FormSet.child_forms = polymorphic_child_forms_factory( + formset_children, **child_kwargs + ) return FormSet diff --git a/polymorphic/formsets/models.py b/polymorphic/formsets/models.py index d11c9c5..4e31a81 100644 --- a/polymorphic/formsets/models.py +++ b/polymorphic/formsets/models.py @@ -3,10 +3,18 @@ from collections import OrderedDict from django import forms from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ImproperlyConfigured, ValidationError -from django.forms.models import ModelForm, BaseModelFormSet, BaseInlineFormSet, modelform_factory, modelformset_factory, inlineformset_factory +from django.forms.models import ( + BaseInlineFormSet, + BaseModelFormSet, + ModelForm, + inlineformset_factory, + modelform_factory, + modelformset_factory, +) from django.utils.functional import cached_property from polymorphic.models import PolymorphicModel + from .utils import add_media @@ -20,9 +28,19 @@ class PolymorphicFormSetChild(object): Provide this information in the :func:'polymorphic_inlineformset_factory' construction. """ - def __init__(self, model, form=ModelForm, fields=None, exclude=None, - formfield_callback=None, widgets=None, localized_fields=None, - labels=None, help_texts=None, error_messages=None): + def __init__( + self, + model, + form=ModelForm, + fields=None, + exclude=None, + formfield_callback=None, + widgets=None, + localized_fields=None, + labels=None, + help_texts=None, + error_messages=None, + ): self.model = model @@ -59,20 +77,20 @@ class PolymorphicFormSetChild(object): # we allow to define things like 'extra_...' fields that are amended to the current child settings. exclude = list(self.exclude) - extra_exclude = kwargs.pop('extra_exclude', None) + extra_exclude = kwargs.pop("extra_exclude", None) if extra_exclude: exclude += list(extra_exclude) defaults = { - 'form': self._form_base, - 'formfield_callback': self.formfield_callback, - 'fields': self.fields, - 'exclude': exclude, + "form": self._form_base, + "formfield_callback": self.formfield_callback, + "fields": self.fields, + "exclude": exclude, # 'for_concrete_model': for_concrete_model, - 'localized_fields': self.localized_fields, - 'labels': self.labels, - 'help_texts': self.help_texts, - 'error_messages': self.error_messages, + "localized_fields": self.localized_fields, + "labels": self.labels, + "help_texts": self.help_texts, + "error_messages": self.error_messages, # 'field_classes': field_classes, } defaults.update(kwargs) @@ -125,61 +143,71 @@ class BasePolymorphicModelFormSet(BaseModelFormSet): pk_field = self.model._meta.pk to_python = self._get_to_python(pk_field) pk = to_python(pk) - kwargs['instance'] = self._existing_object(pk) - if i < self.initial_form_count() and 'instance' not in kwargs: - kwargs['instance'] = self.get_queryset()[i] + kwargs["instance"] = self._existing_object(pk) + if i < self.initial_form_count() and "instance" not in kwargs: + kwargs["instance"] = self.get_queryset()[i] if i >= self.initial_form_count() and self.initial_extra: # Set initial values for extra forms try: - kwargs['initial'] = self.initial_extra[i - self.initial_form_count()] + kwargs["initial"] = self.initial_extra[i - self.initial_form_count()] except IndexError: pass # BaseFormSet logic, with custom formset_class defaults = { - 'auto_id': self.auto_id, - 'prefix': self.add_prefix(i), - 'error_class': self.error_class, + "auto_id": self.auto_id, + "prefix": self.add_prefix(i), + "error_class": self.error_class, } if self.is_bound: - defaults['data'] = self.data - defaults['files'] = self.files - if self.initial and 'initial' not in kwargs: + defaults["data"] = self.data + defaults["files"] = self.files + if self.initial and "initial" not in kwargs: try: - defaults['initial'] = self.initial[i] + defaults["initial"] = self.initial[i] except IndexError: pass # Allow extra forms to be empty, unless they're part of # the minimum forms. if i >= self.initial_form_count() and i >= self.min_num: - defaults['empty_permitted'] = True - defaults['use_required_attribute'] = False + defaults["empty_permitted"] = True + defaults["use_required_attribute"] = False defaults.update(kwargs) # Need to find the model that will be displayed in this form. # Hence, peeking in the self.queryset_data beforehand. if self.is_bound: - if 'instance' in defaults: + if "instance" in defaults: # Object is already bound to a model, won't change the content type - model = defaults['instance'].get_real_instance_class() # allow proxy models + model = defaults[ + "instance" + ].get_real_instance_class() # allow proxy models else: # Extra or empty form, use the provided type. # Note this completely tru - prefix = defaults['prefix'] + prefix = defaults["prefix"] try: ct_id = int(self.data["{0}-polymorphic_ctype".format(prefix)]) except (KeyError, ValueError): - raise ValidationError("Formset row {0} has no 'polymorphic_ctype' defined!".format(prefix)) + raise ValidationError( + "Formset row {0} has no 'polymorphic_ctype' defined!".format( + prefix + ) + ) model = ContentType.objects.get_for_id(ct_id).model_class() if model not in self.child_forms: # Perform basic validation, as we skip the ChoiceField here. - raise UnsupportedChildType("Child model type {0} is not part of the formset".format(model)) + raise UnsupportedChildType( + "Child model type {0} is not part of the formset".format(model) + ) else: - if 'instance' in defaults: - model = defaults['instance'].get_real_instance_class() # allow proxy models - elif 'polymorphic_ctype' in defaults.get('initial', {}): - model = defaults['initial']['polymorphic_ctype'].model_class() + if "instance" in defaults: + model = defaults[ + "instance" + ].get_real_instance_class() # allow proxy models + elif "polymorphic_ctype" in defaults.get("initial", {}): + model = defaults["initial"]["polymorphic_ctype"].model_class() elif i < len(self.queryset_data): model = self.queryset_data[i].__class__ else: @@ -196,9 +224,13 @@ class BasePolymorphicModelFormSet(BaseModelFormSet): def add_fields(self, form, index): """Add a hidden field for the content type.""" - ct = ContentType.objects.get_for_model(form._meta.model, for_concrete_model=False) + ct = ContentType.objects.get_for_model( + form._meta.model, for_concrete_model=False + ) choices = [(ct.pk, ct)] # Single choice, existing forms can't change the value. - form.fields['polymorphic_ctype'] = forms.ChoiceField(choices=choices, initial=ct.pk, required=False, widget=forms.HiddenInput) + form.fields["polymorphic_ctype"] = forms.ChoiceField( + choices=choices, initial=ct.pk, required=False, widget=forms.HiddenInput + ) super(BasePolymorphicModelFormSet, self).add_fields(form, index) def get_form_class(self, model): @@ -206,7 +238,9 @@ class BasePolymorphicModelFormSet(BaseModelFormSet): Return the proper form class for the given model. """ if not self.child_forms: - raise ImproperlyConfigured("No 'child_forms' defined in {0}".format(self.__class__.__name__)) + raise ImproperlyConfigured( + "No 'child_forms' defined in {0}".format(self.__class__.__name__) + ) if not issubclass(model, PolymorphicModel): raise TypeError("Expect polymorphic model type, not {0}".format(model)) @@ -218,7 +252,8 @@ class BasePolymorphicModelFormSet(BaseModelFormSet): "The '{0}' found a '{1}' model in the queryset, " "but no form class is registered to display it.".format( self.__class__.__name__, model.__name__ - )) + ) + ) def is_multipart(self): """ @@ -247,7 +282,7 @@ class BasePolymorphicModelFormSet(BaseModelFormSet): form = form_class( auto_id=self.auto_id, - prefix=self.add_prefix('__prefix__'), + prefix=self.add_prefix("__prefix__"), empty_permitted=True, use_required_attribute=False, **kwargs @@ -259,20 +294,37 @@ class BasePolymorphicModelFormSet(BaseModelFormSet): @property def empty_form(self): # TODO: make an exception when can_add_base is defined? - raise RuntimeError("'empty_form' is not used in polymorphic formsets, use 'empty_forms' instead.") + raise RuntimeError( + "'empty_form' is not used in polymorphic formsets, use 'empty_forms' instead." + ) -def polymorphic_modelformset_factory(model, formset_children, - formset=BasePolymorphicModelFormSet, - # Base field - # TODO: should these fields be removed in favor of creating - # the base form as a formset child too? - form=ModelForm, - fields=None, exclude=None, extra=1, can_order=False, - can_delete=True, max_num=None, formfield_callback=None, - widgets=None, validate_max=False, localized_fields=None, - labels=None, help_texts=None, error_messages=None, - min_num=None, validate_min=False, field_classes=None, child_form_kwargs=None): +def polymorphic_modelformset_factory( + model, + formset_children, + formset=BasePolymorphicModelFormSet, + # Base field + # TODO: should these fields be removed in favor of creating + # the base form as a formset child too? + form=ModelForm, + fields=None, + exclude=None, + extra=1, + can_order=False, + can_delete=True, + max_num=None, + formfield_callback=None, + widgets=None, + validate_max=False, + localized_fields=None, + labels=None, + help_texts=None, + error_messages=None, + min_num=None, + validate_min=False, + field_classes=None, + child_form_kwargs=None, +): """ Construct the class for an polymorphic model formset. @@ -285,25 +337,25 @@ def polymorphic_modelformset_factory(model, formset_children, :rtype: type """ kwargs = { - 'model': model, - 'form': form, - 'formfield_callback': formfield_callback, - 'formset': formset, - 'extra': extra, - 'can_delete': can_delete, - 'can_order': can_order, - 'fields': fields, - 'exclude': exclude, - 'min_num': min_num, - 'max_num': max_num, - 'widgets': widgets, - 'validate_min': validate_min, - 'validate_max': validate_max, - 'localized_fields': localized_fields, - 'labels': labels, - 'help_texts': help_texts, - 'error_messages': error_messages, - 'field_classes': field_classes, + "model": model, + "form": form, + "formfield_callback": formfield_callback, + "formset": formset, + "extra": extra, + "can_delete": can_delete, + "can_order": can_order, + "fields": fields, + "exclude": exclude, + "min_num": min_num, + "max_num": max_num, + "widgets": widgets, + "validate_min": validate_min, + "validate_max": validate_max, + "localized_fields": localized_fields, + "labels": labels, + "help_texts": help_texts, + "error_messages": error_messages, + "field_classes": field_classes, } FormSet = modelformset_factory(**kwargs) @@ -313,7 +365,9 @@ def polymorphic_modelformset_factory(model, formset_children, if child_form_kwargs: child_kwargs.update(child_form_kwargs) - FormSet.child_forms = polymorphic_child_forms_factory(formset_children, **child_kwargs) + FormSet.child_forms = polymorphic_child_forms_factory( + formset_children, **child_kwargs + ) return FormSet @@ -326,17 +380,34 @@ class BasePolymorphicInlineFormSet(BaseInlineFormSet, BasePolymorphicModelFormSe return super(BasePolymorphicInlineFormSet, self)._construct_form(i, **kwargs) -def polymorphic_inlineformset_factory(parent_model, model, formset_children, - formset=BasePolymorphicInlineFormSet, fk_name=None, - # Base field - # TODO: should these fields be removed in favor of creating - # the base form as a formset child too? - form=ModelForm, - fields=None, exclude=None, extra=1, can_order=False, - can_delete=True, max_num=None, formfield_callback=None, - widgets=None, validate_max=False, localized_fields=None, - labels=None, help_texts=None, error_messages=None, - min_num=None, validate_min=False, field_classes=None, child_form_kwargs=None): +def polymorphic_inlineformset_factory( + parent_model, + model, + formset_children, + formset=BasePolymorphicInlineFormSet, + fk_name=None, + # Base field + # TODO: should these fields be removed in favor of creating + # the base form as a formset child too? + form=ModelForm, + fields=None, + exclude=None, + extra=1, + can_order=False, + can_delete=True, + max_num=None, + formfield_callback=None, + widgets=None, + validate_max=False, + localized_fields=None, + labels=None, + help_texts=None, + error_messages=None, + min_num=None, + validate_min=False, + field_classes=None, + child_form_kwargs=None, +): """ Construct the class for an inline polymorphic formset. @@ -349,27 +420,27 @@ def polymorphic_inlineformset_factory(parent_model, model, formset_children, :rtype: type """ kwargs = { - 'parent_model': parent_model, - 'model': model, - 'form': form, - 'formfield_callback': formfield_callback, - 'formset': formset, - 'fk_name': fk_name, - 'extra': extra, - 'can_delete': can_delete, - 'can_order': can_order, - 'fields': fields, - 'exclude': exclude, - 'min_num': min_num, - 'max_num': max_num, - 'widgets': widgets, - 'validate_min': validate_min, - 'validate_max': validate_max, - 'localized_fields': localized_fields, - 'labels': labels, - 'help_texts': help_texts, - 'error_messages': error_messages, - 'field_classes': field_classes, + "parent_model": parent_model, + "model": model, + "form": form, + "formfield_callback": formfield_callback, + "formset": formset, + "fk_name": fk_name, + "extra": extra, + "can_delete": can_delete, + "can_order": can_order, + "fields": fields, + "exclude": exclude, + "min_num": min_num, + "max_num": max_num, + "widgets": widgets, + "validate_min": validate_min, + "validate_max": validate_max, + "localized_fields": localized_fields, + "labels": labels, + "help_texts": help_texts, + "error_messages": error_messages, + "field_classes": field_classes, } FormSet = inlineformset_factory(**kwargs) @@ -379,5 +450,7 @@ def polymorphic_inlineformset_factory(parent_model, model, formset_children, if child_form_kwargs: child_kwargs.update(child_form_kwargs) - FormSet.child_forms = polymorphic_child_forms_factory(formset_children, **child_kwargs) + FormSet.child_forms = polymorphic_child_forms_factory( + formset_children, **child_kwargs + ) return FormSet diff --git a/polymorphic/managers.py b/polymorphic/managers.py index 863e0a7..ead527f 100644 --- a/polymorphic/managers.py +++ b/polymorphic/managers.py @@ -5,14 +5,11 @@ The manager class for use in the models. from __future__ import unicode_literals from django.db import models + from polymorphic.compat import python_2_unicode_compatible from polymorphic.query import PolymorphicQuerySet - -__all__ = ( - 'PolymorphicManager', - 'PolymorphicQuerySet', -) +__all__ = ("PolymorphicManager", "PolymorphicQuerySet") @python_2_unicode_compatible @@ -23,12 +20,17 @@ class PolymorphicManager(models.Manager): Usually not explicitly needed, except if a custom manager or a custom queryset class is to be used. """ + queryset_class = PolymorphicQuerySet @classmethod def from_queryset(cls, queryset_class, class_name=None): - manager = super(PolymorphicManager, cls).from_queryset(queryset_class, class_name=class_name) - manager.queryset_class = queryset_class # also set our version, Django uses _queryset_class + manager = super(PolymorphicManager, cls).from_queryset( + queryset_class, class_name=class_name + ) + manager.queryset_class = ( + queryset_class + ) # also set our version, Django uses _queryset_class return manager def get_queryset(self): @@ -38,7 +40,10 @@ class PolymorphicManager(models.Manager): return qs def __str__(self): - return '%s (PolymorphicManager) using %s' % (self.__class__.__name__, self.queryset_class.__name__) + return "%s (PolymorphicManager) using %s" % ( + self.__class__.__name__, + self.queryset_class.__name__, + ) # Proxied methods def non_polymorphic(self): diff --git a/polymorphic/models.py b/polymorphic/models.py index a0bac80..d396969 100644 --- a/polymorphic/models.py +++ b/polymorphic/models.py @@ -6,10 +6,14 @@ from __future__ import absolute_import from django.contrib.contenttypes.models import ContentType from django.db import models -from django.db.models.fields.related import ReverseOneToOneDescriptor, ForwardManyToOneDescriptor +from django.db.models.fields.related import ( + ForwardManyToOneDescriptor, + ReverseOneToOneDescriptor, +) from django.db.utils import DEFAULT_DB_ALIAS from polymorphic.compat import with_metaclass + from .base import PolymorphicModelBase from .managers import PolymorphicManager from .query_translate import translate_polymorphic_Q_object @@ -44,12 +48,15 @@ class PolymorphicModel(with_metaclass(PolymorphicModelBase, models.Model)): # avoid ContentType related field accessor clash (an error emitted by model validation) #: The model field that stores the :class:`~django.contrib.contenttypes.models.ContentType` reference to the actual class. polymorphic_ctype = models.ForeignKey( - ContentType, null=True, editable=False, on_delete=models.CASCADE, - related_name='polymorphic_%(app_label)s.%(class)s_set+' + ContentType, + null=True, + editable=False, + on_delete=models.CASCADE, + related_name="polymorphic_%(app_label)s.%(class)s_set+", ) # some applications want to know the name of the fields that are added to its models - polymorphic_internal_model_fields = ['polymorphic_ctype'] + polymorphic_internal_model_fields = ["polymorphic_ctype"] # Note that Django 1.5 removes these managers because the model is abstract. # They are pretended to be there by the metaclass in PolymorphicModelBase.get_inherited_managers() @@ -73,14 +80,18 @@ class PolymorphicModel(with_metaclass(PolymorphicModelBase, models.Model)): # field to figure out the real class of this object # (used by PolymorphicQuerySet._get_real_instances) if not self.polymorphic_ctype_id: - self.polymorphic_ctype = ContentType.objects.db_manager(using).get_for_model(self, for_concrete_model=False) + self.polymorphic_ctype = ContentType.objects.db_manager( + using + ).get_for_model(self, for_concrete_model=False) + pre_save_polymorphic.alters_data = True def save(self, *args, **kwargs): """Calls :meth:`pre_save_polymorphic` and saves the model.""" - using = kwargs.get('using', self._state.db or DEFAULT_DB_ALIAS) + using = kwargs.get("using", self._state.db or DEFAULT_DB_ALIAS) self.pre_save_polymorphic(using=using) return super(PolymorphicModel, self).save(*args, **kwargs) + save.alters_data = True def get_real_instance_class(self): @@ -92,28 +103,40 @@ class PolymorphicModel(with_metaclass(PolymorphicModelBase, models.Model)): determined using this method. """ if self.polymorphic_ctype_id is None: - raise PolymorphicTypeUndefined(( - "The model {}#{} does not have a `polymorphic_ctype_id` value defined.\n" - "If you created models outside polymorphic, e.g. through an import or migration, " - "make sure the `polymorphic_ctype_id` field points to the ContentType ID of the model subclass." - ).format(self.__class__.__name__, self.pk)) + raise PolymorphicTypeUndefined( + ( + "The model {}#{} does not have a `polymorphic_ctype_id` value defined.\n" + "If you created models outside polymorphic, e.g. through an import or migration, " + "make sure the `polymorphic_ctype_id` field points to the ContentType ID of the model subclass." + ).format(self.__class__.__name__, self.pk) + ) # the following line would be the easiest way to do this, but it produces sql queries # return self.polymorphic_ctype.model_class() # so we use the following version, which uses the ContentType manager cache. # Note that model_class() can return None for stale content types; # when the content type record still exists but no longer refers to an existing model. - model = ContentType.objects.db_manager(self._state.db).get_for_id(self.polymorphic_ctype_id).model_class() + model = ( + ContentType.objects.db_manager(self._state.db) + .get_for_id(self.polymorphic_ctype_id) + .model_class() + ) # Protect against bad imports (dumpdata without --natural) or other # issues missing with the ContentType models. - if model is not None \ - and not issubclass(model, self.__class__) \ - and (self.__class__._meta.proxy_for_model is None \ - or not issubclass(model, self.__class__._meta.proxy_for_model)): - raise PolymorphicTypeInvalid("ContentType {0} for {1} #{2} does not point to a subclass!".format( - self.polymorphic_ctype_id, model, self.pk, - )) + if ( + model is not None + and not issubclass(model, self.__class__) + and ( + self.__class__._meta.proxy_for_model is None + or not issubclass(model, self.__class__._meta.proxy_for_model) + ) + ): + raise PolymorphicTypeInvalid( + "ContentType {0} for {1} #{2} does not point to a subclass!".format( + self.polymorphic_ctype_id, model, self.pk + ) + ) return model @@ -121,13 +144,21 @@ class PolymorphicModel(with_metaclass(PolymorphicModelBase, models.Model)): model_class = self.get_real_instance_class() if model_class is None: return None - return ContentType.objects.db_manager(self._state.db).get_for_model(model_class, for_concrete_model=True).pk + return ( + ContentType.objects.db_manager(self._state.db) + .get_for_model(model_class, for_concrete_model=True) + .pk + ) def get_real_concrete_instance_class(self): model_class = self.get_real_instance_class() if model_class is None: return None - return ContentType.objects.db_manager(self._state.db).get_for_model(model_class, for_concrete_model=True).model_class() + return ( + ContentType.objects.db_manager(self._state.db) + .get_for_model(model_class, for_concrete_model=True) + .model_class() + ) def get_real_instance(self): """ @@ -147,7 +178,7 @@ class PolymorphicModel(with_metaclass(PolymorphicModelBase, models.Model)): return self return real_model.objects.db_manager(self._state.db).get(pk=self.pk) - def __init__(self, * args, ** kwargs): + def __init__(self, *args, **kwargs): """Replace Django's inheritance accessor member functions for our model (self.__class__) with our own versions. We monkey patch them until a patch can be added to Django @@ -166,7 +197,7 @@ class PolymorphicModel(with_metaclass(PolymorphicModelBase, models.Model)): But they should not. So we replace them with our own accessors that use our appropriate base_objects manager. """ - super(PolymorphicModel, self).__init__(*args, ** kwargs) + super(PolymorphicModel, self).__init__(*args, **kwargs) if self.__class__.polymorphic_super_sub_accessors_replaced: return @@ -176,15 +207,25 @@ class PolymorphicModel(with_metaclass(PolymorphicModelBase, models.Model)): def accessor_function(self): attr = model._base_objects.get(pk=self.pk) return attr + return accessor_function - subclasses_and_superclasses_accessors = self._get_inheritance_relation_fields_and_models() + subclasses_and_superclasses_accessors = ( + self._get_inheritance_relation_fields_and_models() + ) for name, model in subclasses_and_superclasses_accessors.items(): # Here be dragons. orig_accessor = getattr(self.__class__, name, None) - if issubclass(type(orig_accessor), (ReverseOneToOneDescriptor, ForwardManyToOneDescriptor)): - setattr(self.__class__, name, property(create_accessor_function_for_model(model, name))) + if issubclass( + type(orig_accessor), + (ReverseOneToOneDescriptor, ForwardManyToOneDescriptor), + ): + setattr( + self.__class__, + name, + property(create_accessor_function_for_model(model, name)), + ) def _get_inheritance_relation_fields_and_models(self): """helper function for __init__: @@ -194,31 +235,45 @@ class PolymorphicModel(with_metaclass(PolymorphicModelBase, models.Model)): result[field_name] = model def add_model_if_regular(model, field_name, result): - if (issubclass(model, models.Model) - and model != models.Model - and model != self.__class__ - and model != PolymorphicModel): + if ( + issubclass(model, models.Model) + and model != models.Model + and model != self.__class__ + and model != PolymorphicModel + ): add_model(model, field_name, result) def add_all_super_models(model, result): for super_cls, field_to_super in model._meta.parents.items(): if field_to_super is not None: # if not a link to a proxy model - field_name = field_to_super.name # the field on model can have a different name to super_cls._meta.module_name, if the field is created manually using 'parent_link' + field_name = ( + field_to_super.name + ) # the field on model can have a different name to super_cls._meta.module_name, if the field is created manually using 'parent_link' add_model_if_regular(super_cls, field_name, result) add_all_super_models(super_cls, result) def add_all_sub_models(super_cls, result): - for sub_cls in super_cls.__subclasses__(): # go through all subclasses of model - if super_cls in sub_cls._meta.parents: # super_cls may not be in sub_cls._meta.parents if super_cls is a proxy model - field_to_super = sub_cls._meta.parents[super_cls] # get the field that links sub_cls to super_cls - if field_to_super is not None: # if filed_to_super is not a link to a proxy model + for ( + sub_cls + ) in super_cls.__subclasses__(): # go through all subclasses of model + if ( + super_cls in sub_cls._meta.parents + ): # super_cls may not be in sub_cls._meta.parents if super_cls is a proxy model + field_to_super = sub_cls._meta.parents[ + super_cls + ] # get the field that links sub_cls to super_cls + if ( + field_to_super is not None + ): # if filed_to_super is not a link to a proxy model super_to_sub_related_field = field_to_super.remote_field if super_to_sub_related_field.related_name is None: # if related name is None the related field is the name of the subclass to_subclass_fieldname = sub_cls.__name__.lower() else: # otherwise use the given related name - to_subclass_fieldname = super_to_sub_related_field.related_name + to_subclass_fieldname = ( + super_to_sub_related_field.related_name + ) add_model_if_regular(sub_cls, to_subclass_fieldname, result) diff --git a/polymorphic/query.py b/polymorphic/query.py index 75d28b3..4116ae0 100644 --- a/polymorphic/query.py +++ b/polymorphic/query.py @@ -12,8 +12,12 @@ from django.db.models import FieldDoesNotExist from django.db.models.query import ModelIterable, Q, QuerySet from . import compat -from .query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args -from .query_translate import translate_polymorphic_field_path, translate_polymorphic_Q_object +from .query_translate import ( + translate_polymorphic_field_path, + translate_polymorphic_filter_definitions_in_args, + translate_polymorphic_filter_definitions_in_kwargs, + translate_polymorphic_Q_object, +) # chunk-size: maximum number of objects requested per db-request # by the polymorphic queryset.iterator() implementation @@ -72,7 +76,7 @@ def transmogrify(cls, obj): """ Upcast a class to a different type without asking questions. """ - if '__init__' not in obj.__dict__: + if "__init__" not in obj.__dict__: # Just assign __class__ to a different value. new = obj new.__class__ = cls @@ -87,6 +91,7 @@ def transmogrify(cls, obj): ################################################################################### # PolymorphicQuerySet + class PolymorphicQuerySet(QuerySet): """ QuerySet for PolymorphicModel @@ -115,14 +120,17 @@ class PolymorphicQuerySet(QuerySet): new.polymorphic_disabled = self.polymorphic_disabled new.polymorphic_deferred_loading = ( copy.copy(self.polymorphic_deferred_loading[0]), - self.polymorphic_deferred_loading[1]) + self.polymorphic_deferred_loading[1], + ) return new def as_manager(cls): from .managers import PolymorphicManager + manager = PolymorphicManager.from_queryset(cls)() manager._built_with_as_manager = True return manager + as_manager.queryset_only = True as_manager = classmethod(as_manager) @@ -154,15 +162,22 @@ class PolymorphicQuerySet(QuerySet): def _filter_or_exclude(self, negate, *args, **kwargs): # We override this internal Django functon as it is used for all filter member functions. - q_objects = translate_polymorphic_filter_definitions_in_args(self.model, args, using=self.db) # the Q objects - additional_args = translate_polymorphic_filter_definitions_in_kwargs(self.model, kwargs, using=self.db) # filter_field='data' - return super(PolymorphicQuerySet, self)._filter_or_exclude(negate, *(list(q_objects) + additional_args), **kwargs) + q_objects = translate_polymorphic_filter_definitions_in_args( + self.model, args, using=self.db + ) # the Q objects + additional_args = translate_polymorphic_filter_definitions_in_kwargs( + self.model, kwargs, using=self.db + ) # filter_field='data' + return super(PolymorphicQuerySet, self)._filter_or_exclude( + negate, *(list(q_objects) + additional_args), **kwargs + ) def order_by(self, *field_names): """translate the field paths in the args, then call vanilla order_by.""" field_names = [ translate_polymorphic_field_path(self.model, a) - if isinstance(a, compat.string_types) else a # allow expressions to pass unchanged + if isinstance(a, compat.string_types) + else a # allow expressions to pass unchanged for a in field_names ] return super(PolymorphicQuerySet, self).order_by(*field_names) @@ -213,8 +228,8 @@ class PolymorphicQuerySet(QuerySet): """ existing, defer = self.polymorphic_deferred_loading field_names = set(field_names) - if 'pk' in field_names: - field_names.remove('pk') + if "pk" in field_names: + field_names.remove("pk") field_names.add(self.model._meta.pk.name) if defer: @@ -228,14 +243,14 @@ class PolymorphicQuerySet(QuerySet): def _process_aggregate_args(self, args, kwargs): """for aggregate and annotate kwargs: allow ModelX___field syntax for kwargs, forbid it for args. Modifies kwargs if needed (these are Aggregate objects, we translate the lookup member variable)""" - ___lookup_assert_msg = 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only' + ___lookup_assert_msg = "PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only" def patch_lookup(a): # The field on which the aggregate operates is # stored inside a complex query expression. if isinstance(a, Q): translate_polymorphic_Q_object(self.model, a) - elif hasattr(a, 'get_source_expressions'): + elif hasattr(a, "get_source_expressions"): for source_expression in a.get_source_expressions(): if source_expression is not None: patch_lookup(source_expression) @@ -246,6 +261,7 @@ class PolymorphicQuerySet(QuerySet): """ *args might be complex expressions too in django 1.8 so the testing for a '___' is rather complex on this one """ if isinstance(a, Q): + def tree_node_test___lookup(my_model, node): " process all children of this Q node " for i in range(len(node.children)): @@ -253,17 +269,17 @@ class PolymorphicQuerySet(QuerySet): if type(child) == tuple: # this Q object child is a tuple => a kwarg like Q( instance_of=ModelB ) - assert '___' not in child[0], ___lookup_assert_msg + assert "___" not in child[0], ___lookup_assert_msg else: # this Q object child is another Q object, recursively process this as well tree_node_test___lookup(my_model, child) tree_node_test___lookup(self.model, a) - elif hasattr(a, 'get_source_expressions'): + elif hasattr(a, "get_source_expressions"): for source_expression in a.get_source_expressions(): test___lookup(source_expression) else: - assert '___' not in a.name, ___lookup_assert_msg + assert "___" not in a.name, ___lookup_assert_msg for a in args: test___lookup(a) @@ -325,7 +341,7 @@ class PolymorphicQuerySet(QuerySet): Finally we re-sort the resulting objects into the correct order and return them as a list. """ - resultlist = [] # polymorphic list of result-objects + resultlist = [] # polymorphic list of result-objects # dict contains one entry per unique model type occurring in result, # in the format idlist_per_model[modelclass]=[list-of-object-ids] @@ -344,8 +360,12 @@ class PolymorphicQuerySet(QuerySet): # - sort base_result_object ids into idlist_per_model lists, depending on their real class; # - store objects that already have the correct class into "results" content_type_manager = ContentType.objects.db_manager(self.db) - self_model_class_id = content_type_manager.get_for_model(self.model, for_concrete_model=False).pk - self_concrete_model_class_id = content_type_manager.get_for_model(self.model, for_concrete_model=True).pk + self_model_class_id = content_type_manager.get_for_model( + self.model, for_concrete_model=False + ).pk + self_concrete_model_class_id = content_type_manager.get_for_model( + self.model, for_concrete_model=True + ).pk for i, base_object in enumerate(base_result_objects): @@ -354,7 +374,9 @@ class PolymorphicQuerySet(QuerySet): resultlist.append(base_object) else: real_concrete_class = base_object.get_real_instance_class() - real_concrete_class_id = base_object.get_real_concrete_instance_class_id() + real_concrete_class_id = ( + base_object.get_real_concrete_instance_class_id() + ) if real_concrete_class_id is None: # Dealing with a stale content type @@ -365,9 +387,15 @@ class PolymorphicQuerySet(QuerySet): resultlist.append(transmogrify(real_concrete_class, base_object)) else: # This model has a concrete derived class, track it for bulk retrieval. - real_concrete_class = content_type_manager.get_for_id(real_concrete_class_id).model_class() - idlist_per_model[real_concrete_class].append(getattr(base_object, pk_name)) - indexlist_per_model[real_concrete_class].append((i, len(resultlist))) + real_concrete_class = content_type_manager.get_for_id( + real_concrete_class_id + ).model_class() + idlist_per_model[real_concrete_class].append( + getattr(base_object, pk_name) + ) + indexlist_per_model[real_concrete_class].append( + (i, len(resultlist)) + ) resultlist.append(None) # For each model in "idlist_per_model" request its objects (the real model) @@ -377,10 +405,12 @@ class PolymorphicQuerySet(QuerySet): # TODO: defer(), only(): support for these would be around here for real_concrete_class, idlist in idlist_per_model.items(): indices = indexlist_per_model[real_concrete_class] - real_objects = real_concrete_class._base_objects.db_manager(self.db).filter(**{ - ('%s__in' % pk_name): idlist, - }) - real_objects.query.select_related = self.query.select_related # copy select related configuration to new qs + real_objects = real_concrete_class._base_objects.db_manager(self.db).filter( + **{("%s__in" % pk_name): idlist} + ) + real_objects.query.select_related = ( + self.query.select_related + ) # copy select related configuration to new qs # Copy deferred fields configuration to the new queryset deferred_loading_fields = [] @@ -388,14 +418,15 @@ class PolymorphicQuerySet(QuerySet): for field in existing_fields: try: translated_field_name = translate_polymorphic_field_path( - real_concrete_class, field) + real_concrete_class, field + ) except AssertionError: - if '___' in field: + if "___" in field: # The originally passed argument to .defer() or .only() # was in the form Model2B___field2, where Model2B is # now a superclass of real_concrete_class. Thus it's # sufficient to just use the field name. - translated_field_name = field.rpartition('___')[-1] + translated_field_name = field.rpartition("___")[-1] # Check if the field does exist. # Ignore deferred fields that don't exist in this subclass type. @@ -407,7 +438,10 @@ class PolymorphicQuerySet(QuerySet): raise deferred_loading_fields.append(translated_field_name) - real_objects.query.deferred_loading = (set(deferred_loading_fields), self.query.deferred_loading[1]) + real_objects.query.deferred_loading = ( + set(deferred_loading_fields), + self.query.deferred_loading[1], + ) real_objects_dict = { getattr(real_object, pk_name): real_object @@ -445,13 +479,17 @@ class PolymorphicQuerySet(QuerySet): # set polymorphic_annotate_names in all objects (currently just used for debugging/printing) if self.query.annotations: - annotate_names = list(self.query.annotations.keys()) # get annotate field list + annotate_names = list( + self.query.annotations.keys() + ) # get annotate field list for real_object in resultlist: real_object.polymorphic_annotate_names = annotate_names # set polymorphic_extra_select_names in all objects (currently just used for debugging/printing) if self.query.extra_select: - extra_select_names = list(self.query.extra_select.keys()) # get extra select field list + extra_select_names = list( + self.query.extra_select.keys() + ) # get extra select field list for real_object in resultlist: real_object.polymorphic_extra_select_names = extra_select_names @@ -460,15 +498,14 @@ class PolymorphicQuerySet(QuerySet): def __repr__(self, *args, **kwargs): if self.model.polymorphic_query_multiline_output: result = [repr(o) for o in self.all()] - return '[ ' + ',\n '.join(result) + ' ]' + return "[ " + ",\n ".join(result) + " ]" else: return super(PolymorphicQuerySet, self).__repr__(*args, **kwargs) class _p_list_class(list): - def __repr__(self, *args, **kwargs): result = [repr(o) for o in self] - return '[ ' + ',\n '.join(result) + ' ]' + return "[ " + ",\n ".join(result) + " ]" def get_real_instances(self, base_result_objects=None): """ diff --git a/polymorphic/query_translate.py b/polymorphic/query_translate.py index e486eeb..cbecf10 100644 --- a/polymorphic/query_translate.py +++ b/polymorphic/query_translate.py @@ -15,18 +15,19 @@ from django.db.models import Q from django.db.models.fields.related import ForeignObjectRel, RelatedField from django.db.utils import DEFAULT_DB_ALIAS - -################################################################################### -# PolymorphicQuerySet support functions - # These functions implement the additional filter- and Q-object functionality. # They form a kind of small framework for easily adding more # functionality to filters and Q objects. # Probably a more general queryset enhancement class could be made out of them. from polymorphic import compat +################################################################################### +# PolymorphicQuerySet support functions -def translate_polymorphic_filter_definitions_in_kwargs(queryset_model, kwargs, using=DEFAULT_DB_ALIAS): + +def translate_polymorphic_filter_definitions_in_kwargs( + queryset_model, kwargs, using=DEFAULT_DB_ALIAS +): """ Translate the keyword argument list for PolymorphicQuerySet.filter() @@ -43,21 +44,25 @@ def translate_polymorphic_filter_definitions_in_kwargs(queryset_model, kwargs, u additional_args = [] for field_path, val in kwargs.copy().items(): # Python 3 needs copy - new_expr = _translate_polymorphic_filter_definition(queryset_model, field_path, val, using=using) + new_expr = _translate_polymorphic_filter_definition( + queryset_model, field_path, val, using=using + ) if type(new_expr) == tuple: # replace kwargs element - del(kwargs[field_path]) + del kwargs[field_path] kwargs[new_expr[0]] = new_expr[1] elif isinstance(new_expr, models.Q): - del(kwargs[field_path]) + del kwargs[field_path] additional_args.append(new_expr) return additional_args -def translate_polymorphic_Q_object(queryset_model, potential_q_object, using=DEFAULT_DB_ALIAS): +def translate_polymorphic_Q_object( + queryset_model, potential_q_object, using=DEFAULT_DB_ALIAS +): def tree_node_correct_field_specs(my_model, node): " process all children of this Q node " for i in range(len(node.children)): @@ -66,7 +71,9 @@ def translate_polymorphic_Q_object(queryset_model, potential_q_object, using=DEF if type(child) == tuple: # this Q object child is a tuple => a kwarg like Q( instance_of=ModelB ) key, val = child - new_expr = _translate_polymorphic_filter_definition(my_model, key, val, using=using) + new_expr = _translate_polymorphic_filter_definition( + my_model, key, val, using=using + ) if new_expr: node.children[i] = new_expr else: @@ -79,7 +86,9 @@ def translate_polymorphic_Q_object(queryset_model, potential_q_object, using=DEF return potential_q_object -def translate_polymorphic_filter_definitions_in_args(queryset_model, args, using=DEFAULT_DB_ALIAS): +def translate_polymorphic_filter_definitions_in_args( + queryset_model, args, using=DEFAULT_DB_ALIAS +): """ Translate the non-keyword argument list for PolymorphicQuerySet.filter() @@ -90,10 +99,15 @@ def translate_polymorphic_filter_definitions_in_args(queryset_model, args, using Returns: modified Q objects """ - return [translate_polymorphic_Q_object(queryset_model, copy.deepcopy(q), using=using) for q in args] + return [ + translate_polymorphic_Q_object(queryset_model, copy.deepcopy(q), using=using) + for q in args + ] -def _translate_polymorphic_filter_definition(queryset_model, field_path, field_val, using=DEFAULT_DB_ALIAS): +def _translate_polymorphic_filter_definition( + queryset_model, field_path, field_val, using=DEFAULT_DB_ALIAS +): """ Translate a keyword argument (field_path=field_val), as used for PolymorphicQuerySet.filter()-like functions (and Q objects). @@ -107,11 +121,11 @@ def _translate_polymorphic_filter_definition(queryset_model, field_path, field_v # handle instance_of expressions or alternatively, # if this is a normal Django filter expression, return None - if field_path == 'instance_of': + if field_path == "instance_of": return create_instanceof_q(field_val, using=using) - elif field_path == 'not_instance_of': + elif field_path == "not_instance_of": return create_instanceof_q(field_val, not_instance_of=True, using=using) - elif '___' not in field_path: + elif "___" not in field_path: return None # no change # filter expression contains '___' (i.e. filter for polymorphic field) @@ -133,23 +147,32 @@ def translate_polymorphic_field_path(queryset_model, field_path): if not isinstance(field_path, compat.string_types): raise ValueError("Expected field name as string: {0}".format(field_path)) - classname, sep, pure_field_path = field_path.partition('___') + classname, sep, pure_field_path = field_path.partition("___") if not sep: return field_path - assert classname, 'PolymorphicModel: %s: bad field specification' % field_path + assert classname, "PolymorphicModel: %s: bad field specification" % field_path negated = False - if classname[0] == '-': + if classname[0] == "-": negated = True - classname = classname.lstrip('-') + classname = classname.lstrip("-") - if '__' in classname: + if "__" in classname: # the user has app label prepended to class name via __ => use Django's get_model function - appname, sep, classname = classname.partition('__') + appname, sep, classname = classname.partition("__") model = apps.get_model(appname, classname) - assert model, 'PolymorphicModel: model %s (in app %s) not found!' % (model.__name__, appname) + assert model, "PolymorphicModel: model %s (in app %s) not found!" % ( + model.__name__, + appname, + ) if not issubclass(model, queryset_model): - e = 'PolymorphicModel: queryset filter error: "' + model.__name__ + '" is not derived from "' + queryset_model.__name__ + '"' + e = ( + 'PolymorphicModel: queryset filter error: "' + + model.__name__ + + '" is not derived from "' + + queryset_model.__name__ + + '"' + ) raise AssertionError(e) else: @@ -171,18 +194,21 @@ def translate_polymorphic_field_path(queryset_model, field_path): submodels = _get_all_sub_models(queryset_model) model = submodels.get(classname, None) - assert model, 'PolymorphicModel: model %s not found (not a subclass of %s)!' % (classname, queryset_model.__name__) + assert model, "PolymorphicModel: model %s not found (not a subclass of %s)!" % ( + classname, + queryset_model.__name__, + ) basepath = _create_base_path(queryset_model, model) if negated: - newpath = '-' + newpath = "-" else: - newpath = '' + newpath = "" newpath += basepath if basepath: - newpath += '__' + newpath += "__" newpath += pure_field_path return newpath @@ -199,11 +225,13 @@ def _get_all_sub_models(base_model): # model name is occurring twice in submodel inheritance tree => Error if model.__name__ in result and model != result[model.__name__]: raise FieldError( - 'PolymorphicModel: model name alone is ambiguous: %s.%s and %s.%s match!\n' - 'In this case, please use the syntax: applabel__ModelName___field' % ( - model._meta.app_label, model.__name__, + "PolymorphicModel: model name alone is ambiguous: %s.%s and %s.%s match!\n" + "In this case, please use the syntax: applabel__ModelName___field" + % ( + model._meta.app_label, + model.__name__, result[model.__name__]._meta.app_label, - result[model.__name__].__name__ + result[model.__name__].__name__, ) ) @@ -225,8 +253,8 @@ def _create_base_path(baseclass, myclass): if b._meta.abstract or b._meta.proxy: return _get_query_related_name(myclass) else: - return path + '__' + _get_query_related_name(myclass) - return '' + return path + "__" + _get_query_related_name(myclass) + return "" def _get_query_related_name(myclass): @@ -256,12 +284,13 @@ def create_instanceof_q(modellist, not_instance_of=False, using=DEFAULT_DB_ALIAS if not isinstance(modellist, (list, tuple)): from .models import PolymorphicModel + if issubclass(modellist, PolymorphicModel): modellist = [modellist] else: raise TypeError( - 'PolymorphicModel: instance_of expects a list of (polymorphic) ' - 'models or a single (polymorphic) model' + "PolymorphicModel: instance_of expects a list of (polymorphic) " + "models or a single (polymorphic) model" ) contenttype_ids = _get_mro_content_type_ids(modellist, using) @@ -274,7 +303,9 @@ def create_instanceof_q(modellist, not_instance_of=False, using=DEFAULT_DB_ALIAS def _get_mro_content_type_ids(models, using): contenttype_ids = set() for model in models: - ct = ContentType.objects.db_manager(using).get_for_model(model, for_concrete_model=False) + ct = ContentType.objects.db_manager(using).get_for_model( + model, for_concrete_model=False + ) contenttype_ids.add(ct.pk) subclasses = model.__subclasses__() if subclasses: diff --git a/polymorphic/showfields.py b/polymorphic/showfields.py index 0b193c4..84c9891 100644 --- a/polymorphic/showfields.py +++ b/polymorphic/showfields.py @@ -6,15 +6,16 @@ from django.db import models from . import compat from .compat import python_2_unicode_compatible - -RE_DEFERRED = re.compile('_Deferred_.*') +RE_DEFERRED = re.compile("_Deferred_.*") @python_2_unicode_compatible class ShowFieldBase(object): """ base class for the ShowField... model mixins, does the work """ - polymorphic_query_multiline_output = True # cause nicer multiline PolymorphicQuery output + polymorphic_query_multiline_output = ( + True + ) # cause nicer multiline PolymorphicQuery output polymorphic_showfield_type = False polymorphic_showfield_content = False @@ -32,24 +33,24 @@ class ShowFieldBase(object): "helper for __unicode__" content = getattr(self, field_name) if self.polymorphic_showfield_old_format: - out = ': ' + out = ": " else: - out = ' ' + out = " " if issubclass(field_type, models.ForeignKey): if content is None: - out += 'None' + out += "None" else: out += content.__class__.__name__ elif issubclass(field_type, models.ManyToManyField): - out += '%d' % content.count() + out += "%d" % content.count() elif isinstance(content, compat.integer_types): out += str(content) elif content is None: - out += 'None' + out += "None" else: txt = str(content) if len(txt) > self.polymorphic_showfield_max_field_width: - txt = txt[:self.polymorphic_showfield_max_field_width - 2] + '..' + txt = txt[: self.polymorphic_showfield_max_field_width - 2] + ".." out += '"' + txt + '"' return out @@ -57,7 +58,10 @@ class ShowFieldBase(object): "helper for __unicode__" done_fields = set() for field in self._meta.fields + self._meta.many_to_many: - if field.name in self.polymorphic_internal_model_fields or '_ptr' in field.name: + if ( + field.name in self.polymorphic_internal_model_fields + or "_ptr" in field.name + ): continue if field.name in done_fields: continue # work around django diamond inheritance problem @@ -66,78 +70,90 @@ class ShowFieldBase(object): out = field.name # if this is the standard primary key named "id", print it as we did with older versions of django_polymorphic - if field.primary_key and field.name == 'id' and type(field) == models.AutoField: - out += ' ' + str(getattr(self, field.name)) + if ( + field.primary_key + and field.name == "id" + and type(field) == models.AutoField + ): + out += " " + str(getattr(self, field.name)) # otherwise, display it just like all other fields (with correct type, shortened content etc.) else: if self.polymorphic_showfield_type: - out += ' (' + type(field).__name__ + out += " (" + type(field).__name__ if field.primary_key: - out += '/pk' - out += ')' + out += "/pk" + out += ")" if self.polymorphic_showfield_content: out += self._showfields_get_content(field.name, type(field)) - parts.append((False, out, ',')) + parts.append((False, out, ",")) def _showfields_add_dynamic_fields(self, field_list, title, parts): "helper for __unicode__" - parts.append((True, '- ' + title, ':')) + parts.append((True, "- " + title, ":")) for field_name in field_list: out = field_name content = getattr(self, field_name) if self.polymorphic_showfield_type: - out += ' (' + type(content).__name__ + ')' + out += " (" + type(content).__name__ + ")" if self.polymorphic_showfield_content: out += self._showfields_get_content(field_name) - parts.append((False, out, ',')) + parts.append((False, out, ",")) def __str__(self): # create list ("parts") containing one tuple for each title/field: # ( bool: new section , item-text , separator to use after item ) # start with model name - parts = [(True, RE_DEFERRED.sub('', self.__class__.__name__), ':')] + parts = [(True, RE_DEFERRED.sub("", self.__class__.__name__), ":")] # add all regular fields self._showfields_add_regular_fields(parts) # add annotate fields - if hasattr(self, 'polymorphic_annotate_names'): - self._showfields_add_dynamic_fields(self.polymorphic_annotate_names, 'Ann', parts) + if hasattr(self, "polymorphic_annotate_names"): + self._showfields_add_dynamic_fields( + self.polymorphic_annotate_names, "Ann", parts + ) # add extra() select fields - if hasattr(self, 'polymorphic_extra_select_names'): - self._showfields_add_dynamic_fields(self.polymorphic_extra_select_names, 'Extra', parts) + if hasattr(self, "polymorphic_extra_select_names"): + self._showfields_add_dynamic_fields( + self.polymorphic_extra_select_names, "Extra", parts + ) if self.polymorphic_showfield_deferred: fields = self.get_deferred_fields() if fields: - parts.append((False, "deferred[{0}]".format(",".join(sorted(fields))), '')) + parts.append( + (False, "deferred[{0}]".format(",".join(sorted(fields))), "") + ) # format result indent = len(self.__class__.__name__) + 5 - indentstr = ''.rjust(indent) - out = '' + indentstr = "".rjust(indent) + out = "" xpos = 0 possible_line_break_pos = None for i in range(len(parts)): new_section, p, separator = parts[i] - final = (i == len(parts) - 1) + final = i == len(parts) - 1 if not final: next_new_section, _, _ = parts[i + 1] - if (self.polymorphic_showfield_max_line_width - and xpos + len(p) > self.polymorphic_showfield_max_line_width - and possible_line_break_pos is not None): + if ( + self.polymorphic_showfield_max_line_width + and xpos + len(p) > self.polymorphic_showfield_max_line_width + and possible_line_break_pos is not None + ): rest = out[possible_line_break_pos:] out = out[:possible_line_break_pos] - out += '\n' + indentstr + rest + out += "\n" + indentstr + rest xpos = indent + len(rest) out += p @@ -147,26 +163,29 @@ class ShowFieldBase(object): if not next_new_section: out += separator xpos += len(separator) - out += ' ' + out += " " xpos += 1 if not new_section: possible_line_break_pos = len(out) - return '<' + out + '>' + return "<" + out + ">" class ShowFieldType(ShowFieldBase): """ model mixin that shows the object's class and it's field types """ + polymorphic_showfield_type = True class ShowFieldContent(ShowFieldBase): """ model mixin that shows the object's class, it's fields and field contents """ + polymorphic_showfield_content = True class ShowFieldTypeAndContent(ShowFieldBase): """ model mixin, like ShowFieldContent, but also show field types """ + polymorphic_showfield_type = True polymorphic_showfield_content = True diff --git a/polymorphic/templatetags/polymorphic_admin_tags.py b/polymorphic/templatetags/polymorphic_admin_tags.py index d0afb5f..9914b84 100644 --- a/polymorphic/templatetags/polymorphic_admin_tags.py +++ b/polymorphic/templatetags/polymorphic_admin_tags.py @@ -1,14 +1,14 @@ from django.template import Library, Node, TemplateSyntaxError + from polymorphic import compat register = Library() class BreadcrumbScope(Node): - def __init__(self, base_opts, nodelist): self.base_opts = base_opts - self.nodelist = nodelist # Note, takes advantage of Node.child_nodelists + self.nodelist = nodelist # Note, takes advantage of Node.child_nodelists @classmethod def parse(cls, parser, token): @@ -16,15 +16,14 @@ class BreadcrumbScope(Node): if len(bits) == 2: (tagname, base_opts) = bits base_opts = parser.compile_filter(base_opts) - nodelist = parser.parse(('endbreadcrumb_scope',)) + nodelist = parser.parse(("endbreadcrumb_scope",)) parser.delete_first_token() - return cls( - base_opts=base_opts, - nodelist=nodelist - ) + return cls(base_opts=base_opts, nodelist=nodelist) else: - raise TemplateSyntaxError("{0} tag expects 1 argument".format(token.contents[0])) + raise TemplateSyntaxError( + "{0} tag expects 1 argument".format(token.contents[0]) + ) def render(self, context): # app_label is really hard to overwrite in the standard Django ModelAdmin. @@ -34,8 +33,8 @@ class BreadcrumbScope(Node): new_vars = {} if base_opts and not isinstance(base_opts, compat.string_types): new_vars = { - 'app_label': base_opts.app_label, # What this is all about - 'opts': base_opts, + "app_label": base_opts.app_label, # What this is all about + "opts": base_opts, } new_scope = context.push() diff --git a/polymorphic/templatetags/polymorphic_formset_tags.py b/polymorphic/templatetags/polymorphic_formset_tags.py index ec0375a..6a78eca 100644 --- a/polymorphic/templatetags/polymorphic_formset_tags.py +++ b/polymorphic/templatetags/polymorphic_formset_tags.py @@ -7,7 +7,6 @@ from django.utils.translation import ugettext from polymorphic.formsets import BasePolymorphicModelFormSet - register = Library() @@ -19,7 +18,7 @@ def include_empty_form(formset): for form in formset: yield form - if hasattr(formset, 'empty_forms'): + if hasattr(formset, "empty_forms"): # BasePolymorphicModelFormSet for form in formset.empty_forms: yield form @@ -40,24 +39,25 @@ def as_script_options(formset): - ``add_text`` - ``show_add_button`` """ - verbose_name = getattr(formset, 'verbose_name', formset.model._meta.verbose_name) + verbose_name = getattr(formset, "verbose_name", formset.model._meta.verbose_name) options = { - 'prefix': formset.prefix, - 'pkFieldName': formset.model._meta.pk.name, - 'addText': getattr(formset, 'add_text', None) or ugettext('Add another %(verbose_name)s') % { - 'verbose_name': capfirst(verbose_name), - }, - 'showAddButton': getattr(formset, 'show_add_button', True), - 'deleteText': ugettext('Delete'), + "prefix": formset.prefix, + "pkFieldName": formset.model._meta.pk.name, + "addText": getattr(formset, "add_text", None) + or ugettext("Add another %(verbose_name)s") + % {"verbose_name": capfirst(verbose_name)}, + "showAddButton": getattr(formset, "show_add_button", True), + "deleteText": ugettext("Delete"), } if isinstance(formset, BasePolymorphicModelFormSet): # Allow to add different types - options['childTypes'] = [ + options["childTypes"] = [ { - 'name': force_text(model._meta.verbose_name), - 'type': model._meta.model_name, - } for model in formset.child_forms.keys() + "name": force_text(model._meta.verbose_name), + "type": model._meta.model_name, + } + for model in formset.child_forms.keys() ] return json.dumps(options) diff --git a/polymorphic/tests/admintestcase.py b/polymorphic/tests/admintestcase.py index 618d8fc..fbedfb6 100644 --- a/polymorphic/tests/admintestcase.py +++ b/polymorphic/tests/admintestcase.py @@ -12,6 +12,7 @@ class AdminTestCase(TestCase): """ Testing the admin site """ + #: The model to test model = None #: The admin class to test @@ -20,7 +21,9 @@ class AdminTestCase(TestCase): @classmethod def setUpClass(cls): super(AdminTestCase, cls).setUpClass() - cls.admin_user = User.objects.create_superuser('admin', 'admin@example.org', password='admin') + cls.admin_user = User.objects.create_superuser( + "admin", "admin@example.org", password="admin" + ) def setUp(self): super(AdminTestCase, self).setUp() @@ -37,9 +40,11 @@ class AdminTestCase(TestCase): def register(self, model): """Decorator, like admin.register()""" + def _dec(admin_class): self.admin_register(model, admin_class) return admin_class + return _dec def admin_register(self, model, admin_site): @@ -48,9 +53,7 @@ class AdminTestCase(TestCase): # Make sure the URLs are reachable by reverse() clear_url_caches() - set_urlconf(tuple([ - url('^tmp-admin/', self.admin_site.urls) - ])) + set_urlconf(tuple([url("^tmp-admin/", self.admin_site.urls)])) def get_admin_instance(self, model): try: @@ -66,40 +69,42 @@ class AdminTestCase(TestCase): def get_add_url(self, model): admin_instance = self.get_admin_instance(model) - return reverse(admin_urlname(admin_instance.opts, 'add')) + return reverse(admin_urlname(admin_instance.opts, "add")) def get_changelist_url(self, model): admin_instance = self.get_admin_instance(model) - return reverse(admin_urlname(admin_instance.opts, 'changelist')) + return reverse(admin_urlname(admin_instance.opts, "changelist")) def get_change_url(self, model, object_id): admin_instance = self.get_admin_instance(model) - return reverse(admin_urlname(admin_instance.opts, 'change'), args=(object_id,)) + return reverse(admin_urlname(admin_instance.opts, "change"), args=(object_id,)) def get_history_url(self, model, object_id): admin_instance = self.get_admin_instance(model) - return reverse(admin_urlname(admin_instance.opts, 'history'), args=(object_id,)) + return reverse(admin_urlname(admin_instance.opts, "history"), args=(object_id,)) def get_delete_url(self, model, object_id): admin_instance = self.get_admin_instance(model) - return reverse(admin_urlname(admin_instance.opts, 'delete'), args=(object_id,)) + return reverse(admin_urlname(admin_instance.opts, "delete"), args=(object_id,)) - def admin_get_add(self, model, qs=''): + def admin_get_add(self, model, qs=""): """ Make a direct "add" call to the admin page, circumvening login checks. """ admin_instance = self.get_admin_instance(model) - request = self.create_admin_request('get', self.get_add_url(model) + qs) + request = self.create_admin_request("get", self.get_add_url(model) + qs) response = admin_instance.add_view(request) self.assertEqual(response.status_code, 200) return response - def admin_post_add(self, model, formdata, qs=''): + def admin_post_add(self, model, formdata, qs=""): """ Make a direct "add" call to the admin page, circumvening login checks. """ admin_instance = self.get_admin_instance(model) - request = self.create_admin_request('post', self.get_add_url(model) + qs, data=formdata) + request = self.create_admin_request( + "post", self.get_add_url(model) + qs, data=formdata + ) response = admin_instance.add_view(request) self.assertFormSuccess(request.path, response) return response @@ -109,7 +114,7 @@ class AdminTestCase(TestCase): Make a direct "add" call to the admin page, circumvening login checks. """ admin_instance = self.get_admin_instance(model) - request = self.create_admin_request('get', self.get_changelist_url(model)) + request = self.create_admin_request("get", self.get_changelist_url(model)) response = admin_instance.changelist_view(request) self.assertEqual(response.status_code, 200) return response @@ -119,7 +124,9 @@ class AdminTestCase(TestCase): Perform a GET request on the admin page """ admin_instance = self.get_admin_instance(model) - request = self.create_admin_request('get', self.get_change_url(model, object_id), data=query, **extra) + request = self.create_admin_request( + "get", self.get_change_url(model, object_id), data=query, **extra + ) response = admin_instance.change_view(request, str(object_id)) self.assertEqual(response.status_code, 200) return response @@ -129,7 +136,9 @@ class AdminTestCase(TestCase): Make a direct "add" call to the admin page, circumvening login checks. """ admin_instance = self.get_admin_instance(model) - request = self.create_admin_request('post', self.get_change_url(model, object_id), data=formdata, **extra) + request = self.create_admin_request( + "post", self.get_change_url(model, object_id), data=formdata, **extra + ) response = admin_instance.change_view(request, str(object_id)) self.assertFormSuccess(request.path, response) return response @@ -139,7 +148,9 @@ class AdminTestCase(TestCase): Perform a GET request on the admin page """ admin_instance = self.get_admin_instance(model) - request = self.create_admin_request('get', self.get_history_url(model, object_id), data=query, **extra) + request = self.create_admin_request( + "get", self.get_history_url(model, object_id), data=query, **extra + ) response = admin_instance.history_view(request, str(object_id)) self.assertEqual(response.status_code, 200) return response @@ -149,7 +160,9 @@ class AdminTestCase(TestCase): Perform a GET request on the admin delete page """ admin_instance = self.get_admin_instance(model) - request = self.create_admin_request('get', self.get_delete_url(model, object_id), data=query, **extra) + request = self.create_admin_request( + "get", self.get_delete_url(model, object_id), data=query, **extra + ) response = admin_instance.delete_view(request, str(object_id)) self.assertEqual(response.status_code, 200) return response @@ -159,12 +172,16 @@ class AdminTestCase(TestCase): Make a direct "add" call to the admin page, circumvening login checks. """ if not extra: - extra = {'data': {'post': 'yes'}} + extra = {"data": {"post": "yes"}} admin_instance = self.get_admin_instance(model) - request = self.create_admin_request('post', self.get_delete_url(model, object_id), **extra) + request = self.create_admin_request( + "post", self.get_delete_url(model, object_id), **extra + ) response = admin_instance.delete_view(request, str(object_id)) - self.assertEqual(response.status_code, 302, "Form errors in calling {0}".format(request.path)) + self.assertEqual( + response.status_code, 302, "Form errors in calling {0}".format(request.path) + ) return response def create_admin_request(self, method, url, data=None, **extra): @@ -174,8 +191,8 @@ class AdminTestCase(TestCase): factory_method = getattr(RequestFactory(), method) if data is not None: - if method != 'get': - data['csrfmiddlewaretoken'] = 'foo' + if method != "get": + data["csrfmiddlewaretoken"] = "foo" dummy_request = factory_method(url, data=data) dummy_request.user = self.admin_user @@ -185,7 +202,7 @@ class AdminTestCase(TestCase): # data = base_data request = factory_method(url, data=data, **extra) - request.COOKIES[settings.CSRF_COOKIE_NAME] = 'foo' + request.COOKIES[settings.CSRF_COOKIE_NAME] = "foo" request.csrf_processing_done = True # Add properties which middleware would typically do @@ -201,14 +218,21 @@ class AdminTestCase(TestCase): self.assertIn(response.status_code, [200, 302]) if response.status_code != 302: context_data = response.context_data - if 'errors' in context_data: - errors = response.context_data['errors'] - elif 'form' in context_data: - errors = context_data['form'].errors + if "errors" in context_data: + errors = response.context_data["errors"] + elif "form" in context_data: + errors = context_data["form"].errors else: raise KeyError("Unknown field for errors in the TemplateResponse!") - self.assertEqual(response.status_code, 302, - "Form errors in calling {0}:\n{1}".format(request_url, errors.as_text())) - self.assertTrue('/login/?next=' not in response['Location'], - "Received login response for {0}".format(request_url)) + self.assertEqual( + response.status_code, + 302, + "Form errors in calling {0}:\n{1}".format( + request_url, errors.as_text() + ), + ) + self.assertTrue( + "/login/?next=" not in response["Location"], + "Received login response for {0}".format(request_url), + ) diff --git a/polymorphic/tests/migrations/0001_initial.py b/polymorphic/tests/migrations/0001_initial.py index 41331a1..4707a36 100644 --- a/polymorphic/tests/migrations/0001_initial.py +++ b/polymorphic/tests/migrations/0001_initial.py @@ -11,1185 +11,2021 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ] + dependencies = [("contenttypes", "0002_remove_content_type_name")] operations = [ migrations.CreateModel( - name='SwappableModel', + name="SwappableModel", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.swappablemodel_set+', to='contenttypes.ContentType')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.swappablemodel_set+", + to="contenttypes.ContentType", + ), + ), ], - options={ - 'swappable': 'POLYMORPHIC_TEST_SWAPPABLE', - }, + options={"swappable": "POLYMORPHIC_TEST_SWAPPABLE"}, ), migrations.CreateModel( - name='Base', + name="Base", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field_b', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field_b", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldType, models.Model), ), migrations.CreateModel( - name='BlogBase', + name="BlogBase", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='BlogEntry', + name="BlogEntry", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('text', models.CharField(max_length=10)), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.blogentry_set+', to='contenttypes.ContentType')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("text", models.CharField(max_length=10)), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.blogentry_set+", + to="contenttypes.ContentType", + ), + ), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='BlogEntry_limit_choices_to', + name="BlogEntry_limit_choices_to", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('text', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("text", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='ChildModelWithManager', + name="ChildModelWithManager", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ) ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, ), migrations.CreateModel( - name='CustomPkBase', + name="CustomPkBase", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('b', models.CharField(max_length=1)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("b", models.CharField(max_length=1)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='DateModel', + name="DateModel", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('date', models.DateTimeField()), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.datemodel_set+', to='contenttypes.ContentType')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("date", models.DateTimeField()), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.datemodel_set+", + to="contenttypes.ContentType", + ), + ), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, ), migrations.CreateModel( - name='Enhance_Base', + name="Enhance_Base", fields=[ - ('base_id', models.AutoField(primary_key=True, serialize=False)), - ('field_b', models.CharField(max_length=10)), + ("base_id", models.AutoField(primary_key=True, serialize=False)), + ("field_b", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='Enhance_Plain', + name="Enhance_Plain", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field_p', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field_p", models.CharField(max_length=10)), ], ), migrations.CreateModel( - name='InitTestModel', + name="InitTestModel", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('bar', models.CharField(max_length=100)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("bar", models.CharField(max_length=100)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldType, models.Model), ), migrations.CreateModel( - name='MgrInheritA', + name="MgrInheritA", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), - ], - managers=[ - ('mgrA', django.db.models.manager.Manager()), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), ], + managers=[("mgrA", django.db.models.manager.Manager())], ), migrations.CreateModel( - name='Model2A', + name="Model2A", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldType, models.Model), ), migrations.CreateModel( - name='ModelExtraA', + name="ModelExtraA", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='ModelExtraExternal', + name="ModelExtraExternal", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('topic', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("topic", models.CharField(max_length=10)), ], ), migrations.CreateModel( - name='ModelFieldNameTest', + name="ModelFieldNameTest", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('modelfieldnametest', models.CharField(max_length=10)), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.modelfieldnametest_set+', to='contenttypes.ContentType')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("modelfieldnametest", models.CharField(max_length=10)), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.modelfieldnametest_set+", + to="contenttypes.ContentType", + ), + ), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldType, models.Model), ), migrations.CreateModel( - name='ModelShow1', + name="ModelShow1", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), - ('m2m', models.ManyToManyField(related_name='_modelshow1_m2m_+', to='tests.ModelShow1')), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.modelshow1_set+', to='contenttypes.ContentType')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), + ( + "m2m", + models.ManyToManyField( + related_name="_modelshow1_m2m_+", to="tests.ModelShow1" + ), + ), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.modelshow1_set+", + to="contenttypes.ContentType", + ), + ), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldType, models.Model), ), migrations.CreateModel( - name='ModelShow1_plain', + name="ModelShow1_plain", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, ), migrations.CreateModel( - name='ModelShow2', + name="ModelShow2", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), - ('m2m', models.ManyToManyField(related_name='_modelshow2_m2m_+', to='tests.ModelShow2')), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.modelshow2_set+', to='contenttypes.ContentType')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), + ( + "m2m", + models.ManyToManyField( + related_name="_modelshow2_m2m_+", to="tests.ModelShow2" + ), + ), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.modelshow2_set+", + to="contenttypes.ContentType", + ), + ), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldContent, models.Model), ), migrations.CreateModel( - name='ModelShow3', + name="ModelShow3", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), - ('m2m', models.ManyToManyField(related_name='_modelshow3_m2m_+', to='tests.ModelShow3')), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.modelshow3_set+', to='contenttypes.ContentType')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), + ( + "m2m", + models.ManyToManyField( + related_name="_modelshow3_m2m_+", to="tests.ModelShow3" + ), + ), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.modelshow3_set+", + to="contenttypes.ContentType", + ), + ), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='ModelUnderRelChild', + name="ModelUnderRelChild", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('_private2', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("_private2", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, ), migrations.CreateModel( - name='ModelUnderRelParent', + name="ModelUnderRelParent", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), - ('_private', models.CharField(max_length=10)), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.modelunderrelparent_set+', to='contenttypes.ContentType')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), + ("_private", models.CharField(max_length=10)), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.modelunderrelparent_set+", + to="contenttypes.ContentType", + ), + ), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, ), migrations.CreateModel( - name='MROBase1', + name="MROBase1", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldType, models.Model), ), migrations.CreateModel( - name='MROBase3', + name="MROBase3", + fields=[("base_3_id", models.AutoField(primary_key=True, serialize=False))], + ), + migrations.CreateModel( + name="One2OneRelatingModel", fields=[ - ('base_3_id', models.AutoField(primary_key=True, serialize=False)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + ), + migrations.CreateModel( + name="ParentModelWithManager", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.parentmodelwithmanager_set+", + to="contenttypes.ContentType", + ), + ), + ], + options={"abstract": False, "base_manager_name": "objects"}, + ), + migrations.CreateModel( + name="PlainA", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), ], ), migrations.CreateModel( - name='One2OneRelatingModel', + name="PlainChildModelWithManager", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - ), - migrations.CreateModel( - name='ParentModelWithManager', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.parentmodelwithmanager_set+', to='contenttypes.ContentType')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - ), - migrations.CreateModel( - name='PlainA', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ) ], ), migrations.CreateModel( - name='PlainChildModelWithManager', + name="PlainParentModelWithManager", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ) ], ), migrations.CreateModel( - name='PlainParentModelWithManager', + name="ProxiedBase", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=10)), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.proxiedbase_set+", + to="contenttypes.ContentType", + ), + ), ], - ), - migrations.CreateModel( - name='ProxiedBase', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=10)), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.proxiedbase_set+', to='contenttypes.ContentType')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='ProxyBase', + name="ProxyBase", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('some_data', models.CharField(max_length=128)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("some_data", models.CharField(max_length=128)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, ), migrations.CreateModel( - name='RelatedNameClash', + name="RelatedNameClash", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.relatednameclash_set+', to='contenttypes.ContentType')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="contenttypes.ContentType", + ), + ), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.relatednameclash_set+", + to="contenttypes.ContentType", + ), + ), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldType, models.Model), ), migrations.CreateModel( - name='RelatingModel', + name="RelatingModel", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ) ], ), migrations.CreateModel( - name='RelationBase', + name="RelationBase", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field_base', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field_base", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='SwappedModel', + name="SwappedModel", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.swappedmodel_set+', to='contenttypes.ContentType')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.swappedmodel_set+", + to="contenttypes.ContentType", + ), + ), ], - options={ - 'abstract': False, - }, + options={"abstract": False}, ), migrations.CreateModel( - name='Top', + name="Top", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=50)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, ), migrations.CreateModel( - name='UUIDPlainA', + name="UUIDPlainA", fields=[ - ('uuid_primary_key', models.UUIDField(default=uuid.uuid1, primary_key=True, serialize=False)), - ('field1', models.CharField(max_length=10)), + ( + "uuid_primary_key", + models.UUIDField( + default=uuid.uuid1, primary_key=True, serialize=False + ), + ), + ("field1", models.CharField(max_length=10)), ], ), migrations.CreateModel( - name='UUIDProject', + name="UUIDProject", fields=[ - ('uuid_primary_key', models.UUIDField(default=uuid.uuid1, primary_key=True, serialize=False)), - ('topic', models.CharField(max_length=30)), + ( + "uuid_primary_key", + models.UUIDField( + default=uuid.uuid1, primary_key=True, serialize=False + ), + ), + ("topic", models.CharField(max_length=30)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, + options={"abstract": False, "base_manager_name": "objects"}, bases=(polymorphic.showfields.ShowFieldTypeAndContent, models.Model), ), migrations.CreateModel( - name='BlogA', + name="BlogA", fields=[ - ('blogbase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.BlogBase')), - ('info', models.CharField(max_length=10)), + ( + "blogbase_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.BlogBase", + ), + ), + ("info", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.blogbase',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.blogbase",), ), migrations.CreateModel( - name='BlogB', + name="BlogB", fields=[ - ('blogbase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.BlogBase')), + ( + "blogbase_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.BlogBase", + ), + ) ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.blogbase',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.blogbase",), ), migrations.CreateModel( - name='CustomPkInherit', + name="CustomPkInherit", fields=[ - ('custompkbase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, to='tests.CustomPkBase')), - ('custom_id', models.AutoField(primary_key=True, serialize=False)), - ('i', models.CharField(max_length=1)), + ( + "custompkbase_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + to="tests.CustomPkBase", + ), + ), + ("custom_id", models.AutoField(primary_key=True, serialize=False)), + ("i", models.CharField(max_length=1)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.custompkbase',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.custompkbase",), ), migrations.CreateModel( - name='Enhance_Inherit', + name="Enhance_Inherit", fields=[ - ('enhance_plain_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, to='tests.Enhance_Plain')), - ('enhance_base_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Enhance_Base')), - ('field_i', models.CharField(max_length=10)), + ( + "enhance_plain_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + to="tests.Enhance_Plain", + ), + ), + ( + "enhance_base_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Enhance_Base", + ), + ), + ("field_i", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.enhance_base', 'tests.enhance_plain'), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.enhance_base", "tests.enhance_plain"), ), migrations.CreateModel( - name='InitTestModelSubclass', + name="InitTestModelSubclass", fields=[ - ('inittestmodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.InitTestModel')), + ( + "inittestmodel_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.InitTestModel", + ), + ) ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.inittestmodel',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.inittestmodel",), ), migrations.CreateModel( - name='MgrInheritB', + name="MgrInheritB", fields=[ - ('mgrinherita_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.MgrInheritA')), - ('field2', models.CharField(max_length=10)), + ( + "mgrinherita_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.MgrInheritA", + ), + ), + ("field2", models.CharField(max_length=10)), ], - bases=('tests.mgrinherita',), + bases=("tests.mgrinherita",), + managers=[("mgrB", django.db.models.manager.Manager())], + ), + migrations.CreateModel( + name="Middle", + fields=[ + ( + "top_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Top", + ), + ), + ("description", models.TextField()), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.top",), + ), + migrations.CreateModel( + name="Model2B", + fields=[ + ( + "model2a_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Model2A", + ), + ), + ("field2", models.CharField(max_length=10)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.model2a",), + ), + migrations.CreateModel( + name="ModelExtraB", + fields=[ + ( + "modelextraa_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.ModelExtraA", + ), + ), + ("field2", models.CharField(max_length=10)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.modelextraa",), + ), + migrations.CreateModel( + name="ModelShow2_plain", + fields=[ + ( + "modelshow1_plain_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.ModelShow1_plain", + ), + ), + ("field2", models.CharField(max_length=10)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.modelshow1_plain",), + ), + migrations.CreateModel( + name="ModelWithMyManager", + fields=[ + ( + "model2a_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Model2A", + ), + ), + ("field4", models.CharField(max_length=10)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=(polymorphic.showfields.ShowFieldTypeAndContent, "tests.model2a"), + ), + migrations.CreateModel( + name="ModelWithMyManager2", + fields=[ + ( + "model2a_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Model2A", + ), + ), + ("field4", models.CharField(max_length=10)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=(polymorphic.showfields.ShowFieldTypeAndContent, "tests.model2a"), + ), + migrations.CreateModel( + name="ModelWithMyManagerDefault", + fields=[ + ( + "model2a_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Model2A", + ), + ), + ("field4", models.CharField(max_length=10)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=(polymorphic.showfields.ShowFieldTypeAndContent, "tests.model2a"), managers=[ - ('mgrB', django.db.models.manager.Manager()), + ("my_objects", django.db.models.manager.Manager()), + ("objects", django.db.models.manager.Manager()), ], ), migrations.CreateModel( - name='Middle', + name="ModelWithMyManagerNoDefault", fields=[ - ('top_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Top')), - ('description', models.TextField()), + ( + "model2a_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Model2A", + ), + ), + ("field4", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.top',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=(polymorphic.showfields.ShowFieldTypeAndContent, "tests.model2a"), ), migrations.CreateModel( - name='Model2B', + name="ModelX", fields=[ - ('model2a_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Model2A')), - ('field2', models.CharField(max_length=10)), + ( + "base_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Base", + ), + ), + ("field_x", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.model2a',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.base",), ), migrations.CreateModel( - name='ModelExtraB', + name="ModelY", fields=[ - ('modelextraa_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.ModelExtraA')), - ('field2', models.CharField(max_length=10)), + ( + "base_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Base", + ), + ), + ("field_y", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.modelextraa',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.base",), ), migrations.CreateModel( - name='ModelShow2_plain', + name="MROBase2", fields=[ - ('modelshow1_plain_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.ModelShow1_plain')), - ('field2', models.CharField(max_length=10)), + ( + "mrobase1_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.MROBase1", + ), + ) ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.modelshow1_plain',), - ), - migrations.CreateModel( - name='ModelWithMyManager', - fields=[ - ('model2a_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Model2A')), - ('field4', models.CharField(max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=(polymorphic.showfields.ShowFieldTypeAndContent, 'tests.model2a'), - ), - migrations.CreateModel( - name='ModelWithMyManager2', - fields=[ - ('model2a_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Model2A')), - ('field4', models.CharField(max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=(polymorphic.showfields.ShowFieldTypeAndContent, 'tests.model2a'), - ), - migrations.CreateModel( - name='ModelWithMyManagerDefault', - fields=[ - ('model2a_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Model2A')), - ('field4', models.CharField(max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=(polymorphic.showfields.ShowFieldTypeAndContent, 'tests.model2a'), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.mrobase1",), managers=[ - ('my_objects', django.db.models.manager.Manager()), - ('objects', django.db.models.manager.Manager()), + ("objects", django.db.models.manager.Manager()), + ("base_objects", django.db.models.manager.Manager()), ], ), migrations.CreateModel( - name='ModelWithMyManagerNoDefault', + name="NonProxyChild", fields=[ - ('model2a_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Model2A')), - ('field4', models.CharField(max_length=10)), + ( + "proxybase_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.ProxyBase", + ), + ), + ("name", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=(polymorphic.showfields.ShowFieldTypeAndContent, 'tests.model2a'), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.proxybase",), ), migrations.CreateModel( - name='ModelX', + name="One2OneRelatingModelDerived", fields=[ - ('base_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Base')), - ('field_x', models.CharField(max_length=10)), + ( + "one2onerelatingmodel_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.One2OneRelatingModel", + ), + ), + ("field2", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.base',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.one2onerelatingmodel",), ), migrations.CreateModel( - name='ModelY', + name="PlainB", fields=[ - ('base_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Base')), - ('field_y', models.CharField(max_length=10)), + ( + "plaina_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.PlainA", + ), + ), + ("field2", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.base',), + bases=("tests.plaina",), ), migrations.CreateModel( - name='MROBase2', + name="RelationA", fields=[ - ('mrobase1_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.MROBase1')), + ( + "relationbase_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.RelationBase", + ), + ), + ("field_a", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.mrobase1',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.relationbase",), + ), + migrations.CreateModel( + name="RelationB", + fields=[ + ( + "relationbase_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.RelationBase", + ), + ), + ("field_b", models.CharField(max_length=10)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.relationbase",), + ), + migrations.CreateModel( + name="TestParentLinkAndRelatedName", + fields=[ + ( + "superclass", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + related_name="related_name_subclass", + serialize=False, + to="tests.ModelShow1_plain", + ), + ) + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.modelshow1_plain",), + ), + migrations.CreateModel( + name="UUIDArtProject", + fields=[ + ( + "uuidproject_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.UUIDProject", + ), + ), + ("artist", models.CharField(max_length=30)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.uuidproject",), + ), + migrations.CreateModel( + name="UUIDPlainB", + fields=[ + ( + "uuidplaina_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.UUIDPlainA", + ), + ), + ("field2", models.CharField(max_length=10)), + ], + bases=("tests.uuidplaina",), + ), + migrations.CreateModel( + name="UUIDResearchProject", + fields=[ + ( + "uuidproject_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.UUIDProject", + ), + ), + ("supervisor", models.CharField(max_length=30)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.uuidproject",), + ), + migrations.AddField( + model_name="uuidproject", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.uuidproject_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="top", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.top_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="relationbase", + name="fk", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="relationbase_set", + to="tests.RelationBase", + ), + ), + migrations.AddField( + model_name="relationbase", + name="m2m", + field=models.ManyToManyField( + related_name="_relationbase_m2m_+", to="tests.RelationBase" + ), + ), + migrations.AddField( + model_name="relationbase", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.relationbase_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="relatingmodel", + name="many2many", + field=models.ManyToManyField(to="tests.Model2A"), + ), + migrations.AddField( + model_name="proxybase", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.proxybase_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="plainchildmodelwithmanager", + name="fk", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="childmodel_set", + to="tests.PlainParentModelWithManager", + ), + ), + migrations.AddField( + model_name="one2onerelatingmodel", + name="one2one", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, to="tests.Model2A" + ), + ), + migrations.AddField( + model_name="one2onerelatingmodel", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.one2onerelatingmodel_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="mrobase1", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.mrobase1_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="modelunderrelchild", + name="parent", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="children", + to="tests.ModelUnderRelParent", + ), + ), + migrations.AddField( + model_name="modelunderrelchild", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.modelunderrelchild_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="modelshow1_plain", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.modelshow1_plain_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="modelextraa", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.modelextraa_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="model2a", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.model2a_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="inittestmodel", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.inittestmodel_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="enhance_base", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.enhance_base_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="custompkbase", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.custompkbase_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="childmodelwithmanager", + name="fk", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="childmodel_set", + to="tests.ParentModelWithManager", + ), + ), + migrations.AddField( + model_name="childmodelwithmanager", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.childmodelwithmanager_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="blogentry_limit_choices_to", + name="blog", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="tests.BlogBase" + ), + ), + migrations.AddField( + model_name="blogentry_limit_choices_to", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.blogentry_limit_choices_to_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="blogbase", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.blogbase_set+", + to="contenttypes.ContentType", + ), + ), + migrations.AddField( + model_name="base", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.base_set+", + to="contenttypes.ContentType", + ), + ), + migrations.CreateModel( + name="ProxyChild", + fields=[], + options={"proxy": True}, + bases=("tests.proxybase",), + ), + migrations.CreateModel( + name="ProxyModelBase", + fields=[], + options={"proxy": True}, + bases=("tests.proxiedbase",), + ), + migrations.CreateModel( + name="Bottom", + fields=[ + ( + "middle_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Middle", + ), + ), + ("author", models.CharField(max_length=50)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.middle",), + ), + migrations.CreateModel( + name="MgrInheritC", + fields=[ + ( + "mgrinheritb_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.MgrInheritB", + ), + ) + ], + bases=(polymorphic.showfields.ShowFieldTypeAndContent, "tests.mgrinheritb"), + ), + migrations.CreateModel( + name="Model2C", + fields=[ + ( + "model2b_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Model2B", + ), + ), + ("field3", models.CharField(max_length=10)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.model2b",), + ), + migrations.CreateModel( + name="ModelExtraC", + fields=[ + ( + "modelextrab_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.ModelExtraB", + ), + ), + ("field3", models.CharField(max_length=10)), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.modelextrab",), + ), + migrations.CreateModel( + name="MRODerived", + fields=[ + ( + "mrobase3_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + to="tests.MROBase3", + ), + ), + ( + "mrobase2_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.MROBase2", + ), + ), + ], + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.mrobase2", "tests.mrobase3"), managers=[ - ('objects', django.db.models.manager.Manager()), - ('base_objects', django.db.models.manager.Manager()), + ("objects", django.db.models.manager.Manager()), + ("base_objects", django.db.models.manager.Manager()), ], ), migrations.CreateModel( - name='NonProxyChild', + name="PlainC", fields=[ - ('proxybase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.ProxyBase')), - ('name', models.CharField(max_length=10)), + ( + "plainb_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.PlainB", + ), + ), + ("field3", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.proxybase',), + bases=("tests.plainb",), ), migrations.CreateModel( - name='One2OneRelatingModelDerived', + name="ProxyModelA", fields=[ - ('one2onerelatingmodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.One2OneRelatingModel')), - ('field2', models.CharField(max_length=10)), + ( + "proxiedbase_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.ProxiedBase", + ), + ), + ("field1", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.one2onerelatingmodel',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.proxymodelbase",), ), migrations.CreateModel( - name='PlainB', + name="ProxyModelB", fields=[ - ('plaina_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.PlainA')), - ('field2', models.CharField(max_length=10)), + ( + "proxiedbase_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.ProxiedBase", + ), + ), + ("field2", models.CharField(max_length=10)), ], - bases=('tests.plaina',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.proxymodelbase",), ), migrations.CreateModel( - name='RelationA', + name="RelationBC", fields=[ - ('relationbase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.RelationBase')), - ('field_a', models.CharField(max_length=10)), + ( + "relationb_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.RelationB", + ), + ), + ("field_c", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.relationbase',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.relationb",), ), migrations.CreateModel( - name='RelationB', + name="UUIDPlainC", fields=[ - ('relationbase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.RelationBase')), - ('field_b', models.CharField(max_length=10)), + ( + "uuidplainb_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.UUIDPlainB", + ), + ), + ("field3", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.relationbase',), - ), - migrations.CreateModel( - name='TestParentLinkAndRelatedName', - fields=[ - ('superclass', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='related_name_subclass', serialize=False, to='tests.ModelShow1_plain')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.modelshow1_plain',), - ), - migrations.CreateModel( - name='UUIDArtProject', - fields=[ - ('uuidproject_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.UUIDProject')), - ('artist', models.CharField(max_length=30)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.uuidproject',), - ), - migrations.CreateModel( - name='UUIDPlainB', - fields=[ - ('uuidplaina_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.UUIDPlainA')), - ('field2', models.CharField(max_length=10)), - ], - bases=('tests.uuidplaina',), - ), - migrations.CreateModel( - name='UUIDResearchProject', - fields=[ - ('uuidproject_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.UUIDProject')), - ('supervisor', models.CharField(max_length=30)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.uuidproject',), + bases=("tests.uuidplainb",), ), migrations.AddField( - model_name='uuidproject', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.uuidproject_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='top', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.top_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='relationbase', - name='fk', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='relationbase_set', to='tests.RelationBase'), - ), - migrations.AddField( - model_name='relationbase', - name='m2m', - field=models.ManyToManyField(related_name='_relationbase_m2m_+', to='tests.RelationBase'), - ), - migrations.AddField( - model_name='relationbase', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.relationbase_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='relatingmodel', - name='many2many', - field=models.ManyToManyField(to='tests.Model2A'), - ), - migrations.AddField( - model_name='proxybase', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.proxybase_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='plainchildmodelwithmanager', - name='fk', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='childmodel_set', to='tests.PlainParentModelWithManager'), - ), - migrations.AddField( - model_name='one2onerelatingmodel', - name='one2one', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='tests.Model2A'), - ), - migrations.AddField( - model_name='one2onerelatingmodel', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.one2onerelatingmodel_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='mrobase1', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.mrobase1_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='modelunderrelchild', - name='parent', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='children', to='tests.ModelUnderRelParent'), - ), - migrations.AddField( - model_name='modelunderrelchild', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.modelunderrelchild_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='modelshow1_plain', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.modelshow1_plain_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='modelextraa', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.modelextraa_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='model2a', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.model2a_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='inittestmodel', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.inittestmodel_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='enhance_base', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.enhance_base_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='custompkbase', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.custompkbase_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='childmodelwithmanager', - name='fk', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='childmodel_set', to='tests.ParentModelWithManager'), - ), - migrations.AddField( - model_name='childmodelwithmanager', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.childmodelwithmanager_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='blogentry_limit_choices_to', - name='blog', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tests.BlogBase'), - ), - migrations.AddField( - model_name='blogentry_limit_choices_to', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.blogentry_limit_choices_to_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='blogbase', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.blogbase_set+', to='contenttypes.ContentType'), - ), - migrations.AddField( - model_name='base', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.base_set+', to='contenttypes.ContentType'), + model_name="blogentry", + name="blog", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="tests.BlogA" + ), ), migrations.CreateModel( - name='ProxyChild', + name="Model2D", fields=[ + ( + "model2c_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.Model2C", + ), + ), + ("field4", models.CharField(max_length=10)), ], - options={ - 'proxy': True, - }, - bases=('tests.proxybase',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.model2c",), ), migrations.CreateModel( - name='ProxyModelBase', + name="InlineModelBase", fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ) ], - options={ - 'proxy': True, - }, - bases=('tests.proxiedbase',), + options={"abstract": False, "base_manager_name": "objects"}, ), migrations.CreateModel( - name='Bottom', + name="InlineParent", fields=[ - ('middle_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Middle')), - ('author', models.CharField(max_length=50)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.middle',), - ), - migrations.CreateModel( - name='MgrInheritC', - fields=[ - ('mgrinheritb_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.MgrInheritB')), - ], - bases=(polymorphic.showfields.ShowFieldTypeAndContent, 'tests.mgrinheritb'), - ), - migrations.CreateModel( - name='Model2C', - fields=[ - ('model2b_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Model2B')), - ('field3', models.CharField(max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.model2b',), - ), - migrations.CreateModel( - name='ModelExtraC', - fields=[ - ('modelextrab_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.ModelExtraB')), - ('field3', models.CharField(max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.modelextrab',), - ), - migrations.CreateModel( - name='MRODerived', - fields=[ - ('mrobase3_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, to='tests.MROBase3')), - ('mrobase2_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.MROBase2')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.mrobase2', 'tests.mrobase3'), - managers=[ - ('objects', django.db.models.manager.Manager()), - ('base_objects', django.db.models.manager.Manager()), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=10)), ], ), migrations.CreateModel( - name='PlainC', + name="InlineModelA", fields=[ - ('plainb_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.PlainB')), - ('field3', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), ], - bases=('tests.plainb',), + options={"abstract": False, "base_manager_name": "objects"}, ), migrations.CreateModel( - name='ProxyModelA', + name="InlineModelB", fields=[ - ('proxiedbase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.ProxiedBase')), - ('field1', models.CharField(max_length=10)), + ( + "inlinemodela_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.InlineModelA", + ), + ), + ("field2", models.CharField(max_length=10)), ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.proxymodelbase',), - ), - migrations.CreateModel( - name='ProxyModelB', - fields=[ - ('proxiedbase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.ProxiedBase')), - ('field2', models.CharField(max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.proxymodelbase',), - ), - migrations.CreateModel( - name='RelationBC', - fields=[ - ('relationb_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.RelationB')), - ('field_c', models.CharField(max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.relationb',), - ), - migrations.CreateModel( - name='UUIDPlainC', - fields=[ - ('uuidplainb_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.UUIDPlainB')), - ('field3', models.CharField(max_length=10)), - ], - bases=('tests.uuidplainb',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.inlinemodela",), ), migrations.AddField( - model_name='blogentry', - name='blog', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tests.BlogA'), - ), - migrations.CreateModel( - name='Model2D', - fields=[ - ('model2c_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.Model2C')), - ('field4', models.CharField(max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.model2c',), - ), - migrations.CreateModel( - name='InlineModelBase', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - ), - migrations.CreateModel( - name='InlineParent', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=10)), - ], - ), - migrations.CreateModel( - name='InlineModelA', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - ), - migrations.CreateModel( - name='InlineModelB', - fields=[ - ('inlinemodela_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.InlineModelA')), - ('field2', models.CharField(max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.inlinemodela',), + model_name="inlinemodela", + name="parent", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="tests.InlineParent", + related_name="inline_children", + ), ), migrations.AddField( - model_name='inlinemodela', - name='parent', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tests.InlineParent', related_name='inline_children'), + model_name="inlinemodela", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.inlinemodela_set+", + to="contenttypes.ContentType", + ), + ), + migrations.CreateModel( + name="ArtProject", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("topic", models.CharField(max_length=30)), + ("artist", models.CharField(max_length=30)), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.artproject_set+", + to="contenttypes.ContentType", + ), + ), + ], + options={"abstract": False}, + ), + migrations.CreateModel( + name="Duck", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=30)), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.duck_set+", + to="contenttypes.ContentType", + ), + ), + ], + options={"abstract": False}, + ), + migrations.CreateModel( + name="MultiTableBase", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=10)), + ], + options={"abstract": False}, + ), + migrations.CreateModel( + name="MultiTableDerived", + fields=[ + ( + "multitablebase_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.MultiTableBase", + ), + ), + ("field2", models.CharField(max_length=10)), + ], + options={"abstract": False}, + bases=("tests.multitablebase",), ), migrations.AddField( - model_name='inlinemodela', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.inlinemodela_set+', to='contenttypes.ContentType'), + model_name="multitablebase", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.multitablebase_set+", + to="contenttypes.ContentType", + ), ), migrations.CreateModel( - name='ArtProject', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('topic', models.CharField(max_length=30)), - ('artist', models.CharField(max_length=30)), - ('polymorphic_ctype', - models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, - related_name='polymorphic_tests.artproject_set+', to='contenttypes.ContentType')), - ], - options={ - 'abstract': False, - }, + name="RedheadDuck", + fields=[], + options={"proxy": True}, + bases=("tests.duck",), ), migrations.CreateModel( - name='Duck', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=30)), - ('polymorphic_ctype', - models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, - related_name='polymorphic_tests.duck_set+', to='contenttypes.ContentType')), - ], - options={ - 'abstract': False, - }, + name="RubberDuck", fields=[], options={"proxy": True}, bases=("tests.duck",) ), migrations.CreateModel( - name='MultiTableBase', + name="SubclassSelectorAbstractBaseModel", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("base_field", models.CharField(default="test_bf", max_length=10)), ], - options={ - 'abstract': False, - }, + options={"abstract": False, "base_manager_name": "objects"}, ), migrations.CreateModel( - name='MultiTableDerived', + name="SubclassSelectorProxyBaseModel", fields=[ - ('multitablebase_ptr', - models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, - primary_key=True, serialize=False, to='tests.MultiTableBase')), - ('field2', models.CharField(max_length=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("base_field", models.CharField(default="test_bf", max_length=10)), + ( + "polymorphic_ctype", + models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.subclassselectorproxybasemodel_set+", + to="contenttypes.ContentType", + ), + ), ], - options={ - 'abstract': False, - }, - bases=('tests.multitablebase',), + options={"abstract": False, "base_manager_name": "objects"}, + ), + migrations.CreateModel( + name="SubclassSelectorAbstractConcreteModel", + fields=[ + ( + "subclassselectorabstractbasemodel_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.SubclassSelectorAbstractBaseModel", + ), + ), + ("abstract_field", models.CharField(default="test_af", max_length=10)), + ("concrete_field", models.CharField(default="test_cf", max_length=10)), + ], + options={"abstract": False}, + bases=("tests.subclassselectorabstractbasemodel",), ), migrations.AddField( - model_name='multitablebase', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, - related_name='polymorphic_tests.multitablebase_set+', - to='contenttypes.ContentType'), + model_name="subclassselectorabstractbasemodel", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_tests.subclassselectorabstractbasemodel_set+", + to="contenttypes.ContentType", + ), ), migrations.CreateModel( - name='RedheadDuck', - fields=[ - ], - options={ - 'proxy': True, - }, - bases=('tests.duck',), + name="SubclassSelectorProxyModel", + fields=[], + options={"proxy": True, "indexes": []}, + bases=("tests.subclassselectorproxybasemodel",), ), migrations.CreateModel( - name='RubberDuck', + name="SubclassSelectorProxyConcreteModel", fields=[ + ( + "subclassselectorproxybasemodel_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="tests.SubclassSelectorProxyBaseModel", + ), + ), + ("concrete_field", models.CharField(default="test_cf", max_length=10)), ], - options={ - 'proxy': True, - }, - bases=('tests.duck',), - ), - migrations.CreateModel( - name='SubclassSelectorAbstractBaseModel', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('base_field', models.CharField(default='test_bf', max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - ), - migrations.CreateModel( - name='SubclassSelectorProxyBaseModel', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('base_field', models.CharField(default='test_bf', max_length=10)), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.subclassselectorproxybasemodel_set+', to='contenttypes.ContentType')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - ), - migrations.CreateModel( - name='SubclassSelectorAbstractConcreteModel', - fields=[ - ('subclassselectorabstractbasemodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.SubclassSelectorAbstractBaseModel')), - ('abstract_field', models.CharField(default='test_af', max_length=10)), - ('concrete_field', models.CharField(default='test_cf', max_length=10)), - ], - options={ - 'abstract': False, - }, - bases=('tests.subclassselectorabstractbasemodel',), - ), - migrations.AddField( - model_name='subclassselectorabstractbasemodel', - name='polymorphic_ctype', - field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.subclassselectorabstractbasemodel_set+', to='contenttypes.ContentType'), - ), - migrations.CreateModel( - name='SubclassSelectorProxyModel', - fields=[ - ], - options={ - 'proxy': True, - 'indexes': [], - }, - bases=('tests.subclassselectorproxybasemodel',), - ), - migrations.CreateModel( - name='SubclassSelectorProxyConcreteModel', - fields=[ - ('subclassselectorproxybasemodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.SubclassSelectorProxyBaseModel')), - ('concrete_field', models.CharField(default='test_cf', max_length=10)), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('tests.subclassselectorproxymodel',), + options={"abstract": False, "base_manager_name": "objects"}, + bases=("tests.subclassselectorproxymodel",), ), ] diff --git a/polymorphic/tests/models.py b/polymorphic/tests/models.py index f866502..8d7cb22 100644 --- a/polymorphic/tests/models.py +++ b/polymorphic/tests/models.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -import django import uuid +import django from django.contrib.contenttypes.models import ContentType from django.db import models from django.db.models.query import QuerySet @@ -9,7 +9,11 @@ from django.db.models.query import QuerySet from polymorphic.managers import PolymorphicManager from polymorphic.models import PolymorphicModel from polymorphic.query import PolymorphicQuerySet -from polymorphic.showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent +from polymorphic.showfields import ( + ShowFieldContent, + ShowFieldType, + ShowFieldTypeAndContent, +) class PlainA(models.Model): @@ -59,17 +63,17 @@ class ModelExtraExternal(models.Model): class ModelShow1(ShowFieldType, PolymorphicModel): field1 = models.CharField(max_length=10) - m2m = models.ManyToManyField('self') + m2m = models.ManyToManyField("self") class ModelShow2(ShowFieldContent, PolymorphicModel): field1 = models.CharField(max_length=10) - m2m = models.ManyToManyField('self') + m2m = models.ManyToManyField("self") class ModelShow3(ShowFieldTypeAndContent, PolymorphicModel): field1 = models.CharField(max_length=10) - m2m = models.ManyToManyField('self') + m2m = models.ManyToManyField("self") class ModelShow1_plain(PolymorphicModel): @@ -108,8 +112,10 @@ class Enhance_Inherit(Enhance_Base, Enhance_Plain): class RelationBase(ShowFieldTypeAndContent, PolymorphicModel): field_base = models.CharField(max_length=10) - fk = models.ForeignKey('self', on_delete=models.CASCADE, null=True, related_name='relationbase_set') - m2m = models.ManyToManyField('self') + fk = models.ForeignKey( + "self", on_delete=models.CASCADE, null=True, related_name="relationbase_set" + ) + m2m = models.ManyToManyField("self") class RelationA(RelationBase): @@ -143,21 +149,24 @@ class ModelUnderRelParent(PolymorphicModel): class ModelUnderRelChild(PolymorphicModel): - parent = models.ForeignKey(ModelUnderRelParent, on_delete=models.CASCADE, related_name='children') + parent = models.ForeignKey( + ModelUnderRelParent, on_delete=models.CASCADE, related_name="children" + ) _private2 = models.CharField(max_length=10) class MyManagerQuerySet(PolymorphicQuerySet): - def my_queryset_foo(self): - return self.all() # Just a method to prove the existance of the custom queryset. + return ( + self.all() + ) # Just a method to prove the existance of the custom queryset. class MyManager(PolymorphicManager): queryset_class = MyManagerQuerySet def get_queryset(self): - return super(MyManager, self).get_queryset().order_by('-field1') + return super(MyManager, self).get_queryset().order_by("-field1") def my_queryset_foo(self): return self.all().my_queryset_foo() @@ -196,12 +205,15 @@ class MROBase2(MROBase1): class MROBase3(models.Model): - base_3_id = models.AutoField(primary_key=True) # make sure 'id' field doesn't clash, detected by Django 1.11 + base_3_id = models.AutoField( + primary_key=True + ) # make sure 'id' field doesn't clash, detected by Django 1.11 objects = models.Manager() class MRODerived(MROBase2, MROBase3): if django.VERSION < (3, 0): + class Meta: manager_inheritance_from_future = True @@ -212,18 +224,20 @@ class ParentModelWithManager(PolymorphicModel): class ChildModelWithManager(PolymorphicModel): # Also test whether foreign keys receive the manager: - fk = models.ForeignKey(ParentModelWithManager, on_delete=models.CASCADE, related_name='childmodel_set') + fk = models.ForeignKey( + ParentModelWithManager, on_delete=models.CASCADE, related_name="childmodel_set" + ) objects = MyManager() class PlainMyManagerQuerySet(QuerySet): - def my_queryset_foo(self): - return self.all() # Just a method to prove the existence of the custom queryset. + return ( + self.all() + ) # Just a method to prove the existence of the custom queryset. class PlainMyManager(models.Manager): - def my_queryset_foo(self): return self.get_queryset().my_queryset_foo() @@ -236,7 +250,11 @@ class PlainParentModelWithManager(models.Model): class PlainChildModelWithManager(models.Model): - fk = models.ForeignKey(PlainParentModelWithManager, on_delete=models.CASCADE, related_name='childmodel_set') + fk = models.ForeignKey( + PlainParentModelWithManager, + on_delete=models.CASCADE, + related_name="childmodel_set", + ) objects = PlainMyManager() @@ -270,14 +288,14 @@ class InitTestModel(ShowFieldType, PolymorphicModel): bar = models.CharField(max_length=100) def __init__(self, *args, **kwargs): - kwargs['bar'] = self.x() + kwargs["bar"] = self.x() super(InitTestModel, self).__init__(*args, **kwargs) class InitTestModelSubclass(InitTestModel): - def x(self): - return 'XYZ' + return "XYZ" + # models from github issue @@ -319,6 +337,7 @@ class UUIDPlainB(UUIDPlainA): class UUIDPlainC(UUIDPlainB): field3 = models.CharField(max_length=10) + # base -> proxy @@ -327,7 +346,6 @@ class ProxyBase(PolymorphicModel): class ProxyChild(ProxyBase): - class Meta: proxy = True @@ -335,6 +353,7 @@ class ProxyChild(ProxyBase): class NonProxyChild(ProxyBase): name = models.CharField(max_length=10) + # base -> proxy -> real models @@ -343,7 +362,6 @@ class ProxiedBase(ShowFieldTypeAndContent, PolymorphicModel): class ProxyModelBase(ProxiedBase): - class Meta: proxy = True @@ -364,14 +382,20 @@ class ProxyModelB(ProxyModelBase): # with related field 'ContentType.relatednameclash_set'." (reported by Andrew Ingram) # fixed with related_name class RelatedNameClash(ShowFieldType, PolymorphicModel): - ctype = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True, editable=False) + ctype = models.ForeignKey( + ContentType, on_delete=models.CASCADE, null=True, editable=False + ) + # class with a parent_link to superclass, and a related_name back to subclass class TestParentLinkAndRelatedName(ModelShow1_plain): superclass = models.OneToOneField( - ModelShow1_plain, on_delete=models.CASCADE, parent_link=True, related_name='related_name_subclass' + ModelShow1_plain, + on_delete=models.CASCADE, + parent_link=True, + related_name="related_name_subclass", ) @@ -398,7 +422,7 @@ class AbstractModel(PolymorphicModel): class SwappableModel(AbstractModel): class Meta: - swappable = 'POLYMORPHIC_TEST_SWAPPABLE' + swappable = "POLYMORPHIC_TEST_SWAPPABLE" class SwappedModel(AbstractModel): @@ -410,7 +434,9 @@ class InlineParent(models.Model): class InlineModelA(PolymorphicModel): - parent = models.ForeignKey(InlineParent, related_name='inline_children', on_delete=models.CASCADE) + parent = models.ForeignKey( + InlineParent, related_name="inline_children", on_delete=models.CASCADE + ) field1 = models.CharField(max_length=10) @@ -434,13 +460,11 @@ class Duck(PolymorphicModel): class RedheadDuck(Duck): - class Meta: proxy = True class RubberDuck(Duck): - class Meta: proxy = True @@ -454,22 +478,22 @@ class MultiTableDerived(MultiTableBase): class SubclassSelectorAbstractBaseModel(PolymorphicModel): - base_field = models.CharField(max_length=10, default='test_bf') + base_field = models.CharField(max_length=10, default="test_bf") class SubclassSelectorAbstractModel(SubclassSelectorAbstractBaseModel): - abstract_field = models.CharField(max_length=10, default='test_af') + abstract_field = models.CharField(max_length=10, default="test_af") class Meta: abstract = True class SubclassSelectorAbstractConcreteModel(SubclassSelectorAbstractModel): - concrete_field = models.CharField(max_length=10, default='test_cf') + concrete_field = models.CharField(max_length=10, default="test_cf") class SubclassSelectorProxyBaseModel(PolymorphicModel): - base_field = models.CharField(max_length=10, default='test_bf') + base_field = models.CharField(max_length=10, default="test_bf") class SubclassSelectorProxyModel(SubclassSelectorProxyBaseModel): @@ -478,4 +502,4 @@ class SubclassSelectorProxyModel(SubclassSelectorProxyBaseModel): class SubclassSelectorProxyConcreteModel(SubclassSelectorProxyModel): - concrete_field = models.CharField(max_length=10, default='test_cf') + concrete_field = models.CharField(max_length=10, default="test_cf") diff --git a/polymorphic/tests/test_admin.py b/polymorphic/tests/test_admin.py index 00ffd67..57a0419 100644 --- a/polymorphic/tests/test_admin.py +++ b/polymorphic/tests/test_admin.py @@ -2,18 +2,31 @@ from django.contrib import admin from django.contrib.contenttypes.models import ContentType from django.utils.html import escape -from polymorphic.admin import PolymorphicChildModelAdmin, PolymorphicChildModelFilter, PolymorphicInlineSupportMixin, \ - PolymorphicParentModelAdmin, StackedPolymorphicInline +from polymorphic.admin import ( + PolymorphicChildModelAdmin, + PolymorphicChildModelFilter, + PolymorphicInlineSupportMixin, + PolymorphicParentModelAdmin, + StackedPolymorphicInline, +) from polymorphic.tests.admintestcase import AdminTestCase -from polymorphic.tests.models import InlineModelA, InlineModelB, InlineParent, Model2A, Model2B, Model2C, Model2D +from polymorphic.tests.models import ( + InlineModelA, + InlineModelB, + InlineParent, + Model2A, + Model2B, + Model2C, + Model2D, +) class PolymorphicAdminTests(AdminTestCase): - def test_admin_registration(self): """ Test how the registration works """ + @self.register(Model2A) class Model2Admin(PolymorphicParentModelAdmin): base_model = Model2A @@ -25,48 +38,42 @@ class PolymorphicAdminTests(AdminTestCase): @self.register(Model2D) class Model2ChildAdmin(PolymorphicChildModelAdmin): base_model = Model2A - base_fieldsets = ( - ("Base fields", { - 'fields': ('field1',) - }), - ) + base_fieldsets = (("Base fields", {"fields": ("field1",)}),) # -- add page ct_id = ContentType.objects.get_for_model(Model2D).pk self.admin_get_add(Model2A) # shows type page - self.admin_get_add(Model2A, qs='?ct_id={}'.format(ct_id)) # shows type page + self.admin_get_add(Model2A, qs="?ct_id={}".format(ct_id)) # shows type page self.admin_get_add(Model2A) # shows type page - self.admin_post_add(Model2A, { - 'field1': 'A', - 'field2': 'B', - 'field3': 'C', - 'field4': 'D' - }, qs='?ct_id={}'.format(ct_id)) + self.admin_post_add( + Model2A, + {"field1": "A", "field2": "B", "field3": "C", "field4": "D"}, + qs="?ct_id={}".format(ct_id), + ) d_obj = Model2A.objects.all()[0] self.assertEqual(d_obj.__class__, Model2D) - self.assertEqual(d_obj.field1, 'A') - self.assertEqual(d_obj.field2, 'B') + self.assertEqual(d_obj.field1, "A") + self.assertEqual(d_obj.field2, "B") # -- list page self.admin_get_changelist(Model2A) # asserts 200 # -- edit response = self.admin_get_change(Model2A, d_obj.pk) - self.assertContains(response, 'field4') - self.admin_post_change(Model2A, d_obj.pk, { - 'field1': 'A2', - 'field2': 'B2', - 'field3': 'C2', - 'field4': 'D2' - }) + self.assertContains(response, "field4") + self.admin_post_change( + Model2A, + d_obj.pk, + {"field1": "A2", "field2": "B2", "field3": "C2", "field4": "D2"}, + ) d_obj.refresh_from_db() - self.assertEqual(d_obj.field1, 'A2') - self.assertEqual(d_obj.field2, 'B2') - self.assertEqual(d_obj.field3, 'C2') - self.assertEqual(d_obj.field4, 'D2') + self.assertEqual(d_obj.field1, "A2") + self.assertEqual(d_obj.field2, "B2") + self.assertEqual(d_obj.field3, "C2") + self.assertEqual(d_obj.field4, "D2") # -- history self.admin_get_history(Model2A, d_obj.pk) @@ -80,6 +87,7 @@ class PolymorphicAdminTests(AdminTestCase): """ Test the registration of inline models. """ + class InlineModelAChild(StackedPolymorphicInline.Child): model = InlineModelA @@ -88,43 +96,46 @@ class PolymorphicAdminTests(AdminTestCase): class Inline(StackedPolymorphicInline): model = InlineModelA - child_inlines = ( - InlineModelAChild, - InlineModelBChild, - ) + child_inlines = (InlineModelAChild, InlineModelBChild) @self.register(InlineParent) class InlineParentAdmin(PolymorphicInlineSupportMixin, admin.ModelAdmin): inlines = (Inline,) - parent = InlineParent.objects.create(title='FOO') + parent = InlineParent.objects.create(title="FOO") self.assertEqual(parent.inline_children.count(), 0) # -- get edit page response = self.admin_get_change(InlineParent, parent.pk) # Make sure the fieldset has the right data exposed in data-inline-formset - self.assertContains(response, 'childTypes') + self.assertContains(response, "childTypes") self.assertContains(response, escape('"type": "inlinemodela"')) self.assertContains(response, escape('"type": "inlinemodelb"')) # -- post edit page - self.admin_post_change(InlineParent, parent.pk, { - 'title': 'FOO2', - 'inline_children-INITIAL_FORMS': 0, - 'inline_children-TOTAL_FORMS': 1, - 'inline_children-MIN_NUM_FORMS': 0, - 'inline_children-MAX_NUM_FORMS': 1000, - 'inline_children-0-parent': parent.pk, - 'inline_children-0-polymorphic_ctype': ContentType.objects.get_for_model(InlineModelB).pk, - 'inline_children-0-field1': 'A2', - 'inline_children-0-field2': 'B2', - }) + self.admin_post_change( + InlineParent, + parent.pk, + { + "title": "FOO2", + "inline_children-INITIAL_FORMS": 0, + "inline_children-TOTAL_FORMS": 1, + "inline_children-MIN_NUM_FORMS": 0, + "inline_children-MAX_NUM_FORMS": 1000, + "inline_children-0-parent": parent.pk, + "inline_children-0-polymorphic_ctype": ContentType.objects.get_for_model( + InlineModelB + ).pk, + "inline_children-0-field1": "A2", + "inline_children-0-field2": "B2", + }, + ) parent.refresh_from_db() - self.assertEqual(parent.title, 'FOO2') + self.assertEqual(parent.title, "FOO2") self.assertEqual(parent.inline_children.count(), 1) child = parent.inline_children.all()[0] self.assertEqual(child.__class__, InlineModelB) - self.assertEqual(child.field1, 'A2') - self.assertEqual(child.field2, 'B2') + self.assertEqual(child.field1, "A2") + self.assertEqual(child.field2, "B2") diff --git a/polymorphic/tests/test_contrib.py b/polymorphic/tests/test_contrib.py index 42997d6..6cb1f52 100644 --- a/polymorphic/tests/test_contrib.py +++ b/polymorphic/tests/test_contrib.py @@ -1,10 +1,7 @@ from unittest import TestCase from polymorphic.contrib.guardian import get_polymorphic_base_content_type -from polymorphic.tests.models import ( - Model2D, - PlainC, -) +from polymorphic.tests.models import Model2D, PlainC class ContribTests(TestCase): @@ -12,20 +9,19 @@ class ContribTests(TestCase): The test suite """ - def test_contrib_guardian(self): # Regular Django inheritance should return the child model content type. obj = PlainC() ctype = get_polymorphic_base_content_type(obj) - self.assertEqual(ctype.name, 'plain c') + self.assertEqual(ctype.name, "plain c") ctype = get_polymorphic_base_content_type(PlainC) - self.assertEqual(ctype.name, 'plain c') + self.assertEqual(ctype.name, "plain c") # Polymorphic inheritance should return the parent model content type. obj = Model2D() ctype = get_polymorphic_base_content_type(obj) - self.assertEqual(ctype.name, 'model2a') + self.assertEqual(ctype.name, "model2a") ctype = get_polymorphic_base_content_type(Model2D) - self.assertEqual(ctype.name, 'model2a') + self.assertEqual(ctype.name, "model2a") diff --git a/polymorphic/tests/test_multidb.py b/polymorphic/tests/test_multidb.py index 31c9fd9..eec9e5a 100644 --- a/polymorphic/tests/test_multidb.py +++ b/polymorphic/tests/test_multidb.py @@ -23,29 +23,29 @@ class MultipleDatabasesTests(TestCase): multi_db = True def test_save_to_non_default_database(self): - Model2A.objects.db_manager('secondary').create(field1='A1') - Model2C(field1='C1', field2='C2', field3='C3').save(using='secondary') - Model2B.objects.create(field1='B1', field2='B2') - Model2D(field1='D1', field2='D2', field3='D3', field4='D4').save() + Model2A.objects.db_manager("secondary").create(field1="A1") + Model2C(field1="C1", field2="C2", field3="C3").save(using="secondary") + Model2B.objects.create(field1="B1", field2="B2") + Model2D(field1="D1", field2="D2", field3="D3", field4="D4").save() self.assertQuerysetEqual( - Model2A.objects.order_by('id'), + Model2A.objects.order_by("id"), [Model2B, Model2D], transform=lambda o: o.__class__, ) self.assertQuerysetEqual( - Model2A.objects.db_manager('secondary').order_by('id'), + Model2A.objects.db_manager("secondary").order_by("id"), [Model2A, Model2C], transform=lambda o: o.__class__, ) def test_instance_of_filter_on_non_default_database(self): - Base.objects.db_manager('secondary').create(field_b='B1') - ModelX.objects.db_manager('secondary').create(field_b='B', field_x='X') - ModelY.objects.db_manager('secondary').create(field_b='Y', field_y='Y') + Base.objects.db_manager("secondary").create(field_b="B1") + ModelX.objects.db_manager("secondary").create(field_b="B", field_x="X") + ModelY.objects.db_manager("secondary").create(field_b="Y", field_y="Y") - objects = Base.objects.db_manager('secondary').filter(instance_of=Base) + objects = Base.objects.db_manager("secondary").filter(instance_of=Base) self.assertQuerysetEqual( objects, [Base, ModelX, ModelY], @@ -54,19 +54,19 @@ class MultipleDatabasesTests(TestCase): ) self.assertQuerysetEqual( - Base.objects.db_manager('secondary').filter(instance_of=ModelX), + Base.objects.db_manager("secondary").filter(instance_of=ModelX), [ModelX], transform=lambda o: o.__class__, ) self.assertQuerysetEqual( - Base.objects.db_manager('secondary').filter(instance_of=ModelY), + Base.objects.db_manager("secondary").filter(instance_of=ModelY), [ModelY], transform=lambda o: o.__class__, ) self.assertQuerysetEqual( - Base.objects.db_manager('secondary').filter( + Base.objects.db_manager("secondary").filter( Q(instance_of=ModelX) | Q(instance_of=ModelY) ), [ModelX, ModelY], @@ -76,10 +76,14 @@ class MultipleDatabasesTests(TestCase): def test_forward_many_to_one_descriptor_on_non_default_database(self): def func(): - blog = BlogA.objects.db_manager('secondary').create(name='Blog', info='Info') - entry = BlogEntry.objects.db_manager('secondary').create(blog=blog, text='Text') + blog = BlogA.objects.db_manager("secondary").create( + name="Blog", info="Info" + ) + entry = BlogEntry.objects.db_manager("secondary").create( + blog=blog, text="Text" + ) ContentType.objects.clear_cache() - entry = BlogEntry.objects.db_manager('secondary').get(pk=entry.id) + entry = BlogEntry.objects.db_manager("secondary").get(pk=entry.id) self.assertEqual(blog, entry.blog) # Ensure no queries are made using the default database. @@ -87,21 +91,27 @@ class MultipleDatabasesTests(TestCase): def test_reverse_many_to_one_descriptor_on_non_default_database(self): def func(): - blog = BlogA.objects.db_manager('secondary').create(name='Blog', info='Info') - entry = BlogEntry.objects.db_manager('secondary').create(blog=blog, text='Text') + blog = BlogA.objects.db_manager("secondary").create( + name="Blog", info="Info" + ) + entry = BlogEntry.objects.db_manager("secondary").create( + blog=blog, text="Text" + ) ContentType.objects.clear_cache() - blog = BlogA.objects.db_manager('secondary').get(pk=blog.id) - self.assertEqual(entry, blog.blogentry_set.using('secondary').get()) + blog = BlogA.objects.db_manager("secondary").get(pk=blog.id) + self.assertEqual(entry, blog.blogentry_set.using("secondary").get()) # Ensure no queries are made using the default database. self.assertNumQueries(0, func) def test_reverse_one_to_one_descriptor_on_non_default_database(self): def func(): - m2a = Model2A.objects.db_manager('secondary').create(field1='A1') - one2one = One2OneRelatingModel.objects.db_manager('secondary').create(one2one=m2a, field1='121') + m2a = Model2A.objects.db_manager("secondary").create(field1="A1") + one2one = One2OneRelatingModel.objects.db_manager("secondary").create( + one2one=m2a, field1="121" + ) ContentType.objects.clear_cache() - m2a = Model2A.objects.db_manager('secondary').get(pk=m2a.id) + m2a = Model2A.objects.db_manager("secondary").get(pk=m2a.id) self.assertEqual(one2one, m2a.one2onerelatingmodel) # Ensure no queries are made using the default database. @@ -109,12 +119,12 @@ class MultipleDatabasesTests(TestCase): def test_many_to_many_descriptor_on_non_default_database(self): def func(): - m2a = Model2A.objects.db_manager('secondary').create(field1='A1') - rm = RelatingModel.objects.db_manager('secondary').create() + m2a = Model2A.objects.db_manager("secondary").create(field1="A1") + rm = RelatingModel.objects.db_manager("secondary").create() rm.many2many.add(m2a) ContentType.objects.clear_cache() - m2a = Model2A.objects.db_manager('secondary').get(pk=m2a.id) - self.assertEqual(rm, m2a.relatingmodel_set.using('secondary').get()) + m2a = Model2A.objects.db_manager("secondary").get(pk=m2a.id) + self.assertEqual(rm, m2a.relatingmodel_set.using("secondary").get()) # Ensure no queries are made using the default database. self.assertNumQueries(0, func) diff --git a/polymorphic/tests/test_orm.py b/polymorphic/tests/test_orm.py index eb73479..af73b95 100644 --- a/polymorphic/tests/test_orm.py +++ b/polymorphic/tests/test_orm.py @@ -24,7 +24,6 @@ from polymorphic.tests.models import ( Enhance_Base, Enhance_Inherit, InitTestModelSubclass, - MRODerived, Model2A, Model2B, Model2C, @@ -47,6 +46,7 @@ from polymorphic.tests.models import ( ModelWithMyManagerNoDefault, ModelX, ModelY, + MRODerived, MultiTableDerived, MyManager, MyManagerQuerySet, @@ -68,11 +68,11 @@ from polymorphic.tests.models import ( ProxyModelB, ProxyModelBase, RedheadDuck, + RelatingModel, RelationA, RelationB, - RelationBC, RelationBase, - RelatingModel, + RelationBC, RubberDuck, SubclassSelectorAbstractBaseModel, SubclassSelectorAbstractConcreteModel, @@ -97,33 +97,33 @@ class PolymorphicTests(TransactionTestCase): # create a blog of type BlogA # create two blog entries in BlogA # create some blogs of type BlogB to make the BlogBase table data really polymorphic - blog = BlogA.objects.create(name='B1', info='i1') - blog.blogentry_set.create(text='bla') - BlogEntry.objects.create(blog=blog, text='bla2') - BlogB.objects.create(name='Bb1') - BlogB.objects.create(name='Bb2') - BlogB.objects.create(name='Bb3') + blog = BlogA.objects.create(name="B1", info="i1") + blog.blogentry_set.create(text="bla") + BlogEntry.objects.create(blog=blog, text="bla2") + BlogB.objects.create(name="Bb1") + BlogB.objects.create(name="Bb2") + BlogB.objects.create(name="Bb3") - qs = BlogBase.objects.annotate(entrycount=Count('BlogA___blogentry')) + qs = BlogBase.objects.annotate(entrycount=Count("BlogA___blogentry")) self.assertEqual(len(qs), 4) for o in qs: - if o.name == 'B1': + if o.name == "B1": self.assertEqual(o.entrycount, 2) else: self.assertEqual(o.entrycount, 0) - x = BlogBase.objects.aggregate(entrycount=Count('BlogA___blogentry')) - self.assertEqual(x['entrycount'], 2) + x = BlogBase.objects.aggregate(entrycount=Count("BlogA___blogentry")) + self.assertEqual(x["entrycount"], 2) # create some more blogs for next test - BlogA.objects.create(name='B2', info='i2') - BlogA.objects.create(name='B3', info='i3') - BlogA.objects.create(name='B4', info='i4') - BlogA.objects.create(name='B5', info='i5') + BlogA.objects.create(name="B2", info="i2") + BlogA.objects.create(name="B3", info="i3") + BlogA.objects.create(name="B4", info="i4") + BlogA.objects.create(name="B5", info="i5") # test ordering for field in all entries - expected = ''' + expected = """ [ , , , @@ -131,13 +131,13 @@ class PolymorphicTests(TransactionTestCase): , , , - ]''' - x = '\n' + repr(BlogBase.objects.order_by('-name')) + ]""" + x = "\n" + repr(BlogBase.objects.order_by("-name")) self.assertEqual(x, expected) # test ordering for field in one subclass only # MySQL and SQLite return this order - expected1 = ''' + expected1 = """ [ , , , @@ -145,10 +145,10 @@ class PolymorphicTests(TransactionTestCase): , , , - ]''' + ]""" # PostgreSQL returns this order - expected2 = ''' + expected2 = """ [ , , , @@ -156,9 +156,9 @@ class PolymorphicTests(TransactionTestCase): , , , - ]''' + ]""" - x = '\n' + repr(BlogBase.objects.order_by('-BlogA___info')) + x = "\n" + repr(BlogBase.objects.order_by("-BlogA___info")) self.assertTrue(x == expected1 or x == expected2) def test_limit_choices_to(self): @@ -166,11 +166,11 @@ class PolymorphicTests(TransactionTestCase): this is not really a testcase, as limit_choices_to only affects the Django admin """ # create a blog of type BlogA - blog_a = BlogA.objects.create(name='aa', info='aa') - blog_b = BlogB.objects.create(name='bb') + blog_a = BlogA.objects.create(name="aa", info="aa") + blog_b = BlogB.objects.create(name="bb") # create two blog entries - entry1 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2') - entry2 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2') + entry1 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text="bla2") + entry2 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text="bla2") def test_primary_key_custom_field_problem(self): """ @@ -178,7 +178,9 @@ class PolymorphicTests(TransactionTestCase): """ UUIDProject.objects.create(topic="John's gathering") UUIDArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner") - UUIDResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter") + UUIDResearchProject.objects.create( + topic="Swallow Aerodynamics", supervisor="Dr. Winter" + ) qs = UUIDProject.objects.all() ol = list(qs) @@ -189,15 +191,15 @@ class PolymorphicTests(TransactionTestCase): self.assertIsInstance(a.uuid_primary_key, uuid.UUID) self.assertIsInstance(a.pk, uuid.UUID) - res = re.sub(' "(.*?)..", topic', ', topic', repr(qs)) + res = re.sub(' "(.*?)..", topic', ", topic", repr(qs)) res_exp = """[ , , ]""" self.assertEqual(res, res_exp) - a = UUIDPlainA.objects.create(field1='A1') - b = UUIDPlainB.objects.create(field1='B1', field2='B2') - c = UUIDPlainC.objects.create(field1='C1', field2='C2', field3='C3') + a = UUIDPlainA.objects.create(field1="A1") + b = UUIDPlainB.objects.create(field1="B1", field2="B2") + c = UUIDPlainC.objects.create(field1="C1", field2="C2", field3="C3") qs = UUIDPlainA.objects.all() # Test that primary key values are valid UUIDs self.assertEqual(uuid.UUID("urn:uuid:%s" % a.pk, version=1), a.pk) @@ -208,10 +210,10 @@ class PolymorphicTests(TransactionTestCase): Create the chain of objects of Model2, this is reused in various tests. """ - a = Model2A.objects.create(field1='A1') - b = Model2B.objects.create(field1='B1', field2='B2') - c = Model2C.objects.create(field1='C1', field2='C2', field3='C3') - d = Model2D.objects.create(field1='D1', field2='D2', field3='D3', field4='D4') + a = Model2A.objects.create(field1="A1") + b = Model2B.objects.create(field1="B1", field2="B2") + c = Model2C.objects.create(field1="C1", field2="C2", field3="C3") + d = Model2D.objects.create(field1="D1", field2="D2", field3="D3", field4="D4") return a, b, c, d @@ -229,71 +231,115 @@ class PolymorphicTests(TransactionTestCase): def test_defer_fields(self): self.create_model2abcd() - objects_deferred = Model2A.objects.defer('field1').order_by('id') + objects_deferred = Model2A.objects.defer("field1").order_by("id") - self.assertNotIn('field1', objects_deferred[0].__dict__, 'field1 was not deferred (using defer())') - self.assertRegex(repr(objects_deferred[0]), - r'') - self.assertRegex(repr(objects_deferred[1]), - r'') - self.assertRegex(repr(objects_deferred[2]), - r'') - self.assertRegex(repr(objects_deferred[3]), - r'') + self.assertNotIn( + "field1", + objects_deferred[0].__dict__, + "field1 was not deferred (using defer())", + ) + self.assertRegex( + repr(objects_deferred[0]), + r"", + ) + self.assertRegex( + repr(objects_deferred[1]), + r"", + ) + self.assertRegex( + repr(objects_deferred[2]), + r"", + ) + self.assertRegex( + repr(objects_deferred[3]), + r"", + ) - objects_only = Model2A.objects.only('pk', 'polymorphic_ctype', 'field1') + objects_only = Model2A.objects.only("pk", "polymorphic_ctype", "field1") - self.assertIn('field1', objects_only[0].__dict__, - 'qs.only("field1") was used, but field1 was incorrectly deferred') - self.assertIn('field1', objects_only[3].__dict__, - 'qs.only("field1") was used, but field1 was incorrectly deferred' - ' on a child model') - self.assertNotIn('field4', objects_only[3].__dict__, - 'field4 was not deferred (using only())') - self.assertRegex(repr(objects_only[0]), - r'') - self.assertRegex(repr(objects_only[1]), - r'') - self.assertRegex(repr(objects_only[2]), - r'') - self.assertRegex(repr(objects_only[3]), - r'') + self.assertIn( + "field1", + objects_only[0].__dict__, + 'qs.only("field1") was used, but field1 was incorrectly deferred', + ) + self.assertIn( + "field1", + objects_only[3].__dict__, + 'qs.only("field1") was used, but field1 was incorrectly deferred' + " on a child model", + ) + self.assertNotIn( + "field4", objects_only[3].__dict__, "field4 was not deferred (using only())" + ) + self.assertRegex( + repr(objects_only[0]), r"" + ) + self.assertRegex( + repr(objects_only[1]), + r"", + ) + self.assertRegex( + repr(objects_only[2]), + r"", + ) + self.assertRegex( + repr(objects_only[3]), + r"", + ) ModelX.objects.create(field_b="A1", field_x="A2") ModelY.objects.create(field_b="B1", field_y="B2") - objects_deferred = Base.objects.defer('ModelY___field_y') - self.assertRegex(repr(objects_deferred[0]), - r'') - self.assertRegex(repr(objects_deferred[1]), - r'') + objects_deferred = Base.objects.defer("ModelY___field_y") + self.assertRegex( + repr(objects_deferred[0]), + r"", + ) + self.assertRegex( + repr(objects_deferred[1]), + r"", + ) objects_only = Base.objects.only( - 'polymorphic_ctype', 'ModelY___field_y', 'ModelX___field_x', + "polymorphic_ctype", "ModelY___field_y", "ModelX___field_x" + ) + self.assertRegex( + repr(objects_only[0]), + r"", + ) + self.assertRegex( + repr(objects_only[1]), + r"", ) - self.assertRegex(repr(objects_only[0]), - r'') - self.assertRegex(repr(objects_only[1]), - r'') def test_defer_related_fields(self): self.create_model2abcd() - objects_deferred_field4 = Model2A.objects.defer('Model2D___field4') - self.assertNotIn('field4', objects_deferred_field4[3].__dict__, - 'field4 was not deferred (using defer(), traversing inheritance)') + objects_deferred_field4 = Model2A.objects.defer("Model2D___field4") + self.assertNotIn( + "field4", + objects_deferred_field4[3].__dict__, + "field4 was not deferred (using defer(), traversing inheritance)", + ) self.assertEqual(objects_deferred_field4[0].__class__, Model2A) self.assertEqual(objects_deferred_field4[1].__class__, Model2B) self.assertEqual(objects_deferred_field4[2].__class__, Model2C) self.assertEqual(objects_deferred_field4[3].__class__, Model2D) objects_only_field4 = Model2A.objects.only( - 'polymorphic_ctype', 'field1', - 'Model2B___id', 'Model2B___field2', 'Model2B___model2a_ptr', - 'Model2C___id', 'Model2C___field3', 'Model2C___model2b_ptr', - 'Model2D___id', 'Model2D___model2c_ptr') + "polymorphic_ctype", + "field1", + "Model2B___id", + "Model2B___field2", + "Model2B___model2a_ptr", + "Model2C___id", + "Model2C___field3", + "Model2C___model2b_ptr", + "Model2D___id", + "Model2D___model2c_ptr", + ) self.assertEqual(objects_only_field4[0].__class__, Model2A) self.assertEqual(objects_only_field4[1].__class__, Model2B) self.assertEqual(objects_only_field4[2].__class__, Model2C) @@ -302,7 +348,7 @@ class PolymorphicTests(TransactionTestCase): def test_manual_get_real_instance(self): self.create_model2abcd() - o = Model2A.objects.non_polymorphic().get(field1='C1') + o = Model2A.objects.non_polymorphic().get(field1="C1") self.assertEqual(o.get_real_instance().__class__, Model2C) def test_non_polymorphic(self): @@ -337,38 +383,34 @@ class PolymorphicTests(TransactionTestCase): # from empty list objects = Model2A.objects.get_real_instances([]) - self.assertQuerysetEqual( - objects, - [], - transform=lambda o: o.__class__, - ) + self.assertQuerysetEqual(objects, [], transform=lambda o: o.__class__) def test_queryset_missing_derived(self): - a = Model2A.objects.create(field1='A1') - b = Model2B.objects.create(field1='B1', field2='B2') - c = Model2C.objects.create(field1='C1', field2='C2', field3='C3') + a = Model2A.objects.create(field1="A1") + b = Model2B.objects.create(field1="B1", field2="B2") + c = Model2C.objects.create(field1="C1", field2="C2", field3="C3") b_base = Model2A.objects.non_polymorphic().get(pk=b.pk) c_base = Model2A.objects.non_polymorphic().get(pk=c.pk) b.delete(keep_parents=True) # e.g. table was truncated - qs_base = Model2A.objects.order_by('field1').non_polymorphic() - qs_polymorphic = Model2A.objects.order_by('field1').all() + qs_base = Model2A.objects.order_by("field1").non_polymorphic() + qs_polymorphic = Model2A.objects.order_by("field1").all() self.assertEqual(list(qs_base), [a, b_base, c_base]) self.assertEqual(list(qs_polymorphic), [a, c]) def test_queryset_missing_contenttype(self): - stale_ct = ContentType.objects.create(app_label='tests', model='nonexisting') - a1 = Model2A.objects.create(field1='A1') - a2 = Model2A.objects.create(field1='A2') - c = Model2C.objects.create(field1='C1', field2='C2', field3='C3') + stale_ct = ContentType.objects.create(app_label="tests", model="nonexisting") + a1 = Model2A.objects.create(field1="A1") + a2 = Model2A.objects.create(field1="A2") + c = Model2C.objects.create(field1="C1", field2="C2", field3="C3") c_base = Model2A.objects.non_polymorphic().get(pk=c.pk) Model2B.objects.filter(pk=a2.pk).update(polymorphic_ctype=stale_ct) - qs_base = Model2A.objects.order_by('field1').non_polymorphic() - qs_polymorphic = Model2A.objects.order_by('field1').all() + qs_base = Model2A.objects.order_by("field1").non_polymorphic() + qs_polymorphic = Model2A.objects.order_by("field1").all() self.assertEqual(list(qs_base), [a1, a2, c_base]) self.assertEqual(list(qs_polymorphic), [a1, a2, c]) @@ -379,52 +421,30 @@ class PolymorphicTests(TransactionTestCase): q = Model2A.translate_polymorphic_Q_object(Q(instance_of=Model2C)) objects = Model2A.objects.filter(q) self.assertQuerysetEqual( - objects, - [Model2C, Model2D], - transform=lambda o: o.__class__, - ordered=False, + objects, [Model2C, Model2D], transform=lambda o: o.__class__, ordered=False ) def test_create_instanceof_q(self): q = query_translate.create_instanceof_q([Model2B]) - expected = sorted([ - ContentType.objects.get_for_model(m).pk - for m in [Model2B, Model2C, Model2D] - ]) + expected = sorted( + [ + ContentType.objects.get_for_model(m).pk + for m in [Model2B, Model2C, Model2D] + ] + ) self.assertEqual(dict(q.children), dict(polymorphic_ctype__in=expected)) def test_base_manager(self): def base_manager(model): - return ( - type(model._base_manager), - model._base_manager.model - ) + return (type(model._base_manager), model._base_manager.model) - self.assertEqual( - base_manager(PlainA), - (models.Manager, PlainA), - ) - self.assertEqual( - base_manager(PlainB), - (models.Manager, PlainB), - ) - self.assertEqual( - base_manager(PlainC), - (models.Manager, PlainC), - ) + self.assertEqual(base_manager(PlainA), (models.Manager, PlainA)) + self.assertEqual(base_manager(PlainB), (models.Manager, PlainB)) + self.assertEqual(base_manager(PlainC), (models.Manager, PlainC)) - self.assertEqual( - base_manager(Model2A), - (PolymorphicManager, Model2A), - ) - self.assertEqual( - base_manager(Model2B), - (PolymorphicManager, Model2B), - ) - self.assertEqual( - base_manager(Model2C), - (PolymorphicManager, Model2C), - ) + self.assertEqual(base_manager(Model2A), (PolymorphicManager, Model2A)) + self.assertEqual(base_manager(Model2B), (PolymorphicManager, Model2B)) + self.assertEqual(base_manager(Model2C), (PolymorphicManager, Model2C)) self.assertEqual( base_manager(One2OneRelatingModel), @@ -439,94 +459,93 @@ class PolymorphicTests(TransactionTestCase): def default_manager(instance): return ( type(instance.__class__._default_manager), - instance.__class__._default_manager.model + instance.__class__._default_manager.model, ) - plain_a = PlainA(field1='C1') - plain_b = PlainB(field2='C1') - plain_c = PlainC(field3='C1') + plain_a = PlainA(field1="C1") + plain_b = PlainB(field2="C1") + plain_c = PlainC(field3="C1") - model_2a = Model2A(field1='C1') - model_2b = Model2B(field2='C1') - model_2c = Model2C(field3='C1') + model_2a = Model2A(field1="C1") + model_2b = Model2B(field2="C1") + model_2c = Model2C(field3="C1") - self.assertEqual( - default_manager(plain_a), - (models.Manager, PlainA), - ) - self.assertEqual( - default_manager(plain_b), - (models.Manager, PlainB), - ) - self.assertEqual( - default_manager(plain_c), - (models.Manager, PlainC), - ) + self.assertEqual(default_manager(plain_a), (models.Manager, PlainA)) + self.assertEqual(default_manager(plain_b), (models.Manager, PlainB)) + self.assertEqual(default_manager(plain_c), (models.Manager, PlainC)) - self.assertEqual( - default_manager(model_2a), - (PolymorphicManager, Model2A), - ) - self.assertEqual( - default_manager(model_2b), - (PolymorphicManager, Model2B), - ) - self.assertEqual( - default_manager(model_2c), - (PolymorphicManager, Model2C), - ) + self.assertEqual(default_manager(model_2a), (PolymorphicManager, Model2A)) + self.assertEqual(default_manager(model_2b), (PolymorphicManager, Model2B)) + self.assertEqual(default_manager(model_2c), (PolymorphicManager, Model2C)) def test_foreignkey_field(self): self.create_model2abcd() - object2a = Model2A.base_objects.get(field1='C1') + object2a = Model2A.base_objects.get(field1="C1") self.assertEqual(object2a.model2b.__class__, Model2B) - object2b = Model2B.base_objects.get(field1='C1') + object2b = Model2B.base_objects.get(field1="C1") self.assertEqual(object2b.model2c.__class__, Model2C) def test_onetoone_field(self): self.create_model2abcd() - a = Model2A.base_objects.get(field1='C1') - b = One2OneRelatingModelDerived.objects.create(one2one=a, field1='f1', field2='f2') + a = Model2A.base_objects.get(field1="C1") + b = One2OneRelatingModelDerived.objects.create( + one2one=a, field1="f1", field2="f2" + ) # this result is basically wrong, probably due to Django cacheing (we used base_objects), but should not be a problem self.assertEqual(b.one2one.__class__, Model2A) self.assertEqual(b.one2one_id, b.one2one.id) - c = One2OneRelatingModelDerived.objects.get(field1='f1') + c = One2OneRelatingModelDerived.objects.get(field1="f1") self.assertEqual(c.one2one.__class__, Model2C) - self.assertEqual( - a.one2onerelatingmodel.__class__, - One2OneRelatingModelDerived, - ) + self.assertEqual(a.one2onerelatingmodel.__class__, One2OneRelatingModelDerived) def test_manytomany_field(self): # Model 1 - o = ModelShow1.objects.create(field1='abc') + o = ModelShow1.objects.create(field1="abc") o.m2m.add(o) o.save() - self.assertEqual(repr(ModelShow1.objects.all()), '[ ]') + self.assertEqual( + repr(ModelShow1.objects.all()), + "[ ]", + ) # Model 2 - o = ModelShow2.objects.create(field1='abc') + o = ModelShow2.objects.create(field1="abc") o.m2m.add(o) o.save() - self.assertEqual(repr(ModelShow2.objects.all()), '[ ]') + self.assertEqual( + repr(ModelShow2.objects.all()), + '[ ]', + ) # Model 3 - o = ModelShow3.objects.create(field1='abc') + o = ModelShow3.objects.create(field1="abc") o.m2m.add(o) o.save() - self.assertEqual(repr(ModelShow3.objects.all()), '[ ]') - self.assertEqual(repr(ModelShow1.objects.all().annotate(Count('m2m'))), '[ ]') - self.assertEqual(repr(ModelShow2.objects.all().annotate(Count('m2m'))), '[ ]') - self.assertEqual(repr(ModelShow3.objects.all().annotate(Count('m2m'))), '[ ]') + self.assertEqual( + repr(ModelShow3.objects.all()), + '[ ]', + ) + self.assertEqual( + repr(ModelShow1.objects.all().annotate(Count("m2m"))), + "[ ]", + ) + self.assertEqual( + repr(ModelShow2.objects.all().annotate(Count("m2m"))), + '[ ]', + ) + self.assertEqual( + repr(ModelShow3.objects.all().annotate(Count("m2m"))), + '[ ]', + ) # no pretty printing - ModelShow1_plain.objects.create(field1='abc') - ModelShow2_plain.objects.create(field1='abc', field2='def') + ModelShow1_plain.objects.create(field1="abc") + ModelShow2_plain.objects.create(field1="abc", field2="def") self.assertQuerysetEqual( ModelShow1_plain.objects.all(), [ModelShow1_plain, ModelShow2_plain], @@ -537,42 +556,57 @@ class PolymorphicTests(TransactionTestCase): def test_extra_method(self): a, b, c, d = self.create_model2abcd() + objects = Model2A.objects.extra(where=["id IN ({}, {})".format(b.id, c.id)]) + self.assertQuerysetEqual( + objects, [Model2B, Model2C], transform=lambda o: o.__class__, ordered=False + ) + objects = Model2A.objects.extra( - where=['id IN ({}, {})'.format(b.id, c.id)] + select={"select_test": "field1 = 'A1'"}, + where=["field1 = 'A1' OR field1 = 'B1'"], + order_by=["-id"], ) self.assertQuerysetEqual( - objects, - [Model2B, Model2C], - transform=lambda o: o.__class__, - ordered=False, + objects, [Model2B, Model2A], transform=lambda o: o.__class__ ) - objects = Model2A.objects.extra(select={"select_test": "field1 = 'A1'"}, where=["field1 = 'A1' OR field1 = 'B1'"], order_by=['-id']) - self.assertQuerysetEqual( - objects, - [Model2B, Model2A], - transform=lambda o: o.__class__, - ) - - ModelExtraA.objects.create(field1='A1') - ModelExtraB.objects.create(field1='B1', field2='B2') - ModelExtraC.objects.create(field1='C1', field2='C2', field3='C3') - ModelExtraExternal.objects.create(topic='extra1') - ModelExtraExternal.objects.create(topic='extra2') - ModelExtraExternal.objects.create(topic='extra3') + ModelExtraA.objects.create(field1="A1") + ModelExtraB.objects.create(field1="B1", field2="B2") + ModelExtraC.objects.create(field1="C1", field2="C2", field3="C3") + ModelExtraExternal.objects.create(topic="extra1") + ModelExtraExternal.objects.create(topic="extra2") + ModelExtraExternal.objects.create(topic="extra3") objects = ModelExtraA.objects.extra( tables=["tests_modelextraexternal"], select={"topic": "tests_modelextraexternal.topic"}, where=["tests_modelextraa.id = tests_modelextraexternal.id"], ) if compat.PY3: - self.assertEqual(repr(objects[0]), '') - self.assertEqual(repr(objects[1]), '') - self.assertEqual(repr(objects[2]), '') + self.assertEqual( + repr(objects[0]), + '', + ) + self.assertEqual( + repr(objects[1]), + '', + ) + self.assertEqual( + repr(objects[2]), + '', + ) else: - self.assertEqual(repr(objects[0]), '') - self.assertEqual(repr(objects[1]), '') - self.assertEqual(repr(objects[2]), '') + self.assertEqual( + repr(objects[0]), + '', + ) + self.assertEqual( + repr(objects[1]), + '', + ) + self.assertEqual( + repr(objects[2]), + '', + ) self.assertEqual(len(objects), 3) def test_instance_of_filter(self): @@ -604,54 +638,49 @@ class PolymorphicTests(TransactionTestCase): objects = Model2A.objects.not_instance_of(Model2B) self.assertQuerysetEqual( - objects, - [Model2A], - transform=lambda o: o.__class__, - ordered=False, + objects, [Model2A], transform=lambda o: o.__class__, ordered=False ) def test_polymorphic___filter(self): self.create_model2abcd() - objects = Model2A.objects.filter(Q(Model2B___field2='B2') | Q(Model2C___field3='C3')) + objects = Model2A.objects.filter( + Q(Model2B___field2="B2") | Q(Model2C___field3="C3") + ) self.assertQuerysetEqual( - objects, - [Model2B, Model2C], - transform=lambda o: o.__class__, - ordered=False, + objects, [Model2B, Model2C], transform=lambda o: o.__class__, ordered=False ) def test_polymorphic_applabel___filter(self): self.create_model2abcd() - assert Model2B._meta.app_label == 'tests' - objects = Model2A.objects.filter(Q(tests__Model2B___field2='B2') | Q(tests__Model2C___field3='C3')) + assert Model2B._meta.app_label == "tests" + objects = Model2A.objects.filter( + Q(tests__Model2B___field2="B2") | Q(tests__Model2C___field3="C3") + ) self.assertQuerysetEqual( - objects, - [Model2B, Model2C], - transform=lambda o: o.__class__, - ordered=False, + objects, [Model2B, Model2C], transform=lambda o: o.__class__, ordered=False ) def test_query_filter_exclude_is_immutable(self): # given - q_to_reuse = Q(Model2B___field2='something') - untouched_q_object = Q(Model2B___field2='something') + q_to_reuse = Q(Model2B___field2="something") + untouched_q_object = Q(Model2B___field2="something") # when Model2A.objects.filter(q_to_reuse).all() # then self.assertEqual(q_to_reuse.children, untouched_q_object.children) # given - q_to_reuse = Q(Model2B___field2='something') - untouched_q_object = Q(Model2B___field2='something') + q_to_reuse = Q(Model2B___field2="something") + untouched_q_object = Q(Model2B___field2="something") # when Model2B.objects.filter(q_to_reuse).all() # then self.assertEqual(q_to_reuse.children, untouched_q_object.children) def test_polymorphic___filter_field(self): - p = ModelUnderRelParent.objects.create(_private=True, field1='AA') + p = ModelUnderRelParent.objects.create(_private=True, field1="AA") ModelUnderRelChild.objects.create(parent=p, _private2=True) # The "___" filter should also parse to "parent" -> "_private" as fallback. @@ -659,7 +688,7 @@ class PolymorphicTests(TransactionTestCase): self.assertEqual(len(objects), 1) def test_polymorphic___filter_reverse_field(self): - p = ModelUnderRelParent.objects.create(_private=True, field1='BB') + p = ModelUnderRelParent.objects.create(_private=True, field1="BB") ModelUnderRelChild.objects.create(parent=p, _private2=True) # Also test for reverse relations @@ -683,71 +712,112 @@ class PolymorphicTests(TransactionTestCase): ) def test_combine_querysets(self): - ModelX.objects.create(field_x='x', field_b='1') - ModelY.objects.create(field_y='y', field_b='2') + ModelX.objects.create(field_x="x", field_b="1") + ModelY.objects.create(field_y="y", field_b="2") qs = Base.objects.instance_of(ModelX) | Base.objects.instance_of(ModelY) - qs = qs.order_by('field_b') - self.assertEqual(repr(qs[0]), '') - self.assertEqual(repr(qs[1]), '') + qs = qs.order_by("field_b") + self.assertEqual( + repr(qs[0]), "" + ) + self.assertEqual( + repr(qs[1]), "" + ) self.assertEqual(len(qs), 2) def test_multiple_inheritance(self): # multiple inheritance, subclassing third party models (mix PolymorphicModel with models.Model) - Enhance_Base.objects.create(field_b='b-base') - Enhance_Inherit.objects.create(field_b='b-inherit', field_p='p', field_i='i') + Enhance_Base.objects.create(field_b="b-base") + Enhance_Inherit.objects.create(field_b="b-inherit", field_p="p", field_i="i") qs = Enhance_Base.objects.all() self.assertEqual(len(qs), 2) - self.assertEqual(repr(qs[0]), '') - self.assertEqual(repr(qs[1]), '') + self.assertEqual( + repr(qs[0]), + '', + ) + self.assertEqual( + repr(qs[1]), + '', + ) def test_relation_base(self): # ForeignKey, ManyToManyField - obase = RelationBase.objects.create(field_base='base') - oa = RelationA.objects.create(field_base='A1', field_a='A2', fk=obase) - ob = RelationB.objects.create(field_base='B1', field_b='B2', fk=oa) - oc = RelationBC.objects.create(field_base='C1', field_b='C2', field_c='C3', fk=oa) + obase = RelationBase.objects.create(field_base="base") + oa = RelationA.objects.create(field_base="A1", field_a="A2", fk=obase) + ob = RelationB.objects.create(field_base="B1", field_b="B2", fk=oa) + oc = RelationBC.objects.create( + field_base="C1", field_b="C2", field_c="C3", fk=oa + ) oa.m2m.add(oa) oa.m2m.add(ob) objects = RelationBase.objects.all() - self.assertEqual(repr(objects[0]), '') - self.assertEqual(repr(objects[1]), '') - self.assertEqual(repr(objects[2]), '') - self.assertEqual(repr(objects[3]), '') + self.assertEqual( + repr(objects[0]), + '', + ) + self.assertEqual( + repr(objects[1]), + '', + ) + self.assertEqual( + repr(objects[2]), + '', + ) + self.assertEqual( + repr(objects[3]), + '', + ) self.assertEqual(len(objects), 4) oa = RelationBase.objects.get(id=2) - self.assertEqual(repr(oa.fk), '') + self.assertEqual( + repr(oa.fk), + '', + ) objects = oa.relationbase_set.all() - self.assertEqual(repr(objects[0]), '') - self.assertEqual(repr(objects[1]), '') + self.assertEqual( + repr(objects[0]), + '', + ) + self.assertEqual( + repr(objects[1]), + '', + ) self.assertEqual(len(objects), 2) ob = RelationBase.objects.get(id=3) - self.assertEqual(repr(ob.fk), '') + self.assertEqual( + repr(ob.fk), + '', + ) oa = RelationA.objects.get() objects = oa.m2m.all() - self.assertEqual(repr(objects[0]), '') - self.assertEqual(repr(objects[1]), '') + self.assertEqual( + repr(objects[0]), + '', + ) + self.assertEqual( + repr(objects[1]), + '', + ) self.assertEqual(len(objects), 2) def test_user_defined_manager(self): self.create_model2abcd() - ModelWithMyManager.objects.create(field1='D1a', field4='D4a') - ModelWithMyManager.objects.create(field1='D1b', field4='D4b') + ModelWithMyManager.objects.create(field1="D1a", field4="D4a") + ModelWithMyManager.objects.create(field1="D1b", field4="D4b") - objects = ModelWithMyManager.objects.all() # MyManager should reverse the sorting of field1 + objects = ( + ModelWithMyManager.objects.all() + ) # MyManager should reverse the sorting of field1 self.assertQuerysetEqual( objects, - [ - (ModelWithMyManager, 'D1b', 'D4b'), - (ModelWithMyManager, 'D1a', 'D4a'), - ], + [(ModelWithMyManager, "D1b", "D4b"), (ModelWithMyManager, "D1a", "D4a")], transform=lambda o: (o.__class__, o.field1, o.field4), ) @@ -757,28 +827,32 @@ class PolymorphicTests(TransactionTestCase): def test_user_defined_manager_as_secondary(self): self.create_model2abcd() - ModelWithMyManagerNoDefault.objects.create(field1='D1a', field4='D4a') - ModelWithMyManagerNoDefault.objects.create(field1='D1b', field4='D4b') + ModelWithMyManagerNoDefault.objects.create(field1="D1a", field4="D4a") + ModelWithMyManagerNoDefault.objects.create(field1="D1b", field4="D4b") - objects = ModelWithMyManagerNoDefault.my_objects.all() # MyManager should reverse the sorting of field1 + objects = ( + ModelWithMyManagerNoDefault.my_objects.all() + ) # MyManager should reverse the sorting of field1 self.assertQuerysetEqual( objects, [ - (ModelWithMyManagerNoDefault, 'D1b', 'D4b'), - (ModelWithMyManagerNoDefault, 'D1a', 'D4a'), + (ModelWithMyManagerNoDefault, "D1b", "D4b"), + (ModelWithMyManagerNoDefault, "D1a", "D4a"), ], transform=lambda o: (o.__class__, o.field1, o.field4), ) self.assertIs(type(ModelWithMyManagerNoDefault.my_objects), MyManager) self.assertIs(type(ModelWithMyManagerNoDefault.objects), PolymorphicManager) - self.assertIs(type(ModelWithMyManagerNoDefault._default_manager), PolymorphicManager) + self.assertIs( + type(ModelWithMyManagerNoDefault._default_manager), PolymorphicManager + ) self.assertIs(type(ModelWithMyManagerNoDefault.base_objects), models.Manager) def test_user_objects_manager_as_secondary(self): self.create_model2abcd() - ModelWithMyManagerDefault.objects.create(field1='D1a', field4='D4a') - ModelWithMyManagerDefault.objects.create(field1='D1b', field4='D4b') + ModelWithMyManagerDefault.objects.create(field1="D1a", field4="D4a") + ModelWithMyManagerDefault.objects.create(field1="D1b", field4="D4b") self.assertIs(type(ModelWithMyManagerDefault.my_objects), MyManager) self.assertIs(type(ModelWithMyManagerDefault.objects), PolymorphicManager) @@ -787,22 +861,25 @@ class PolymorphicTests(TransactionTestCase): def test_user_defined_queryset_as_manager(self): self.create_model2abcd() - ModelWithMyManager2.objects.create(field1='D1a', field4='D4a') - ModelWithMyManager2.objects.create(field1='D1b', field4='D4b') + ModelWithMyManager2.objects.create(field1="D1a", field4="D4a") + ModelWithMyManager2.objects.create(field1="D1b", field4="D4b") objects = ModelWithMyManager2.objects.all() self.assertQuerysetEqual( objects, - [ - (ModelWithMyManager2, 'D1a', 'D4a'), - (ModelWithMyManager2, 'D1b', 'D4b'), - ], + [(ModelWithMyManager2, "D1a", "D4a"), (ModelWithMyManager2, "D1b", "D4b")], transform=lambda o: (o.__class__, o.field1, o.field4), ordered=False, ) - self.assertEqual(type(ModelWithMyManager2.objects).__name__, 'PolymorphicManagerFromMyManagerQuerySet') - self.assertEqual(type(ModelWithMyManager2._default_manager).__name__, 'PolymorphicManagerFromMyManagerQuerySet') + self.assertEqual( + type(ModelWithMyManager2.objects).__name__, + "PolymorphicManagerFromMyManagerQuerySet", + ) + self.assertEqual( + type(ModelWithMyManager2._default_manager).__name__, + "PolymorphicManagerFromMyManagerQuerySet", + ) self.assertIs(type(ModelWithMyManager2.base_objects), models.Manager) def test_manager_inheritance(self): @@ -813,13 +890,19 @@ class PolymorphicTests(TransactionTestCase): # This is just a consistency check for now, testing standard Django behavior. parent = PlainParentModelWithManager.objects.create() child = PlainChildModelWithManager.objects.create(fk=parent) - self.assertIs(type(PlainParentModelWithManager._default_manager), models.Manager) + self.assertIs( + type(PlainParentModelWithManager._default_manager), models.Manager + ) self.assertIs(type(PlainChildModelWithManager._default_manager), PlainMyManager) self.assertIs(type(PlainChildModelWithManager.objects), PlainMyManager) - self.assertIs(type(PlainChildModelWithManager.objects.all()), PlainMyManagerQuerySet) + self.assertIs( + type(PlainChildModelWithManager.objects.all()), PlainMyManagerQuerySet + ) # A related set is created using the model's _default_manager, so does gain extra methods. - self.assertIs(type(parent.childmodel_set.my_queryset_foo()), PlainMyManagerQuerySet) + self.assertIs( + type(parent.childmodel_set.my_queryset_foo()), PlainMyManagerQuerySet + ) # For polymorphic models, the same should happen. parent = ParentModelWithManager.objects.create() @@ -827,14 +910,16 @@ class PolymorphicTests(TransactionTestCase): self.assertIs(type(ParentModelWithManager._default_manager), PolymorphicManager) self.assertIs(type(ChildModelWithManager._default_manager), MyManager) self.assertIs(type(ChildModelWithManager.objects), MyManager) - self.assertIs(type(ChildModelWithManager.objects.my_queryset_foo()), MyManagerQuerySet) + self.assertIs( + type(ChildModelWithManager.objects.my_queryset_foo()), MyManagerQuerySet + ) # A related set is created using the model's _default_manager, so does gain extra methods. self.assertIs(type(parent.childmodel_set.my_queryset_foo()), MyManagerQuerySet) def test_proxy_models(self): # prepare some data - for data in ('bleep bloop', 'I am a', 'computer'): + for data in ("bleep bloop", "I am a", "computer"): ProxyChild.objects.create(some_data=data) # this caches ContentType queries so they don't interfere with our query counts later @@ -847,11 +932,11 @@ class PolymorphicTests(TransactionTestCase): self.assertIsInstance(items[0], ProxyChild) def test_queryset_on_proxy_model_does_not_return_superclasses(self): - ProxyBase.objects.create(some_data='Base1') - ProxyBase.objects.create(some_data='Base2') - ProxyChild.objects.create(some_data='Child1') - ProxyChild.objects.create(some_data='Child2') - ProxyChild.objects.create(some_data='Child3') + ProxyBase.objects.create(some_data="Base1") + ProxyBase.objects.create(some_data="Base2") + ProxyChild.objects.create(some_data="Child1") + ProxyChild.objects.create(some_data="Child2") + ProxyChild.objects.create(some_data="Child3") self.assertEqual(5, ProxyBase.objects.count()) self.assertEqual(3, ProxyChild.objects.count()) @@ -898,37 +983,58 @@ class PolymorphicTests(TransactionTestCase): object2_pk = ProxyModelB.objects.create(name="object2", field2="bb").pk # Getting single objects - object1 = ProxyModelBase.objects.get(name='object1') - object2 = ProxyModelBase.objects.get(name='object2') - self.assertEqual(repr(object1), '' % object1_pk) - self.assertEqual(repr(object2), '' % object2_pk) + object1 = ProxyModelBase.objects.get(name="object1") + object2 = ProxyModelBase.objects.get(name="object2") + self.assertEqual( + repr(object1), + '' + % object1_pk, + ) + self.assertEqual( + repr(object2), + '' + % object2_pk, + ) self.assertIsInstance(object1, ProxyModelA) self.assertIsInstance(object2, ProxyModelB) # Same for lists - objects = list(ProxyModelBase.objects.all().order_by('name')) - self.assertEqual(repr(objects[0]), '' % object1_pk) - self.assertEqual(repr(objects[1]), '' % object2_pk) + objects = list(ProxyModelBase.objects.all().order_by("name")) + self.assertEqual( + repr(objects[0]), + '' + % object1_pk, + ) + self.assertEqual( + repr(objects[1]), + '' + % object2_pk, + ) self.assertIsInstance(objects[0], ProxyModelA) self.assertIsInstance(objects[1], ProxyModelB) def test_custom_pk(self): - CustomPkBase.objects.create(b='b') - CustomPkInherit.objects.create(b='b', i='i') + CustomPkBase.objects.create(b="b") + CustomPkInherit.objects.create(b="b", i="i") qs = CustomPkBase.objects.all() self.assertEqual(len(qs), 2) self.assertEqual(repr(qs[0]), '') - self.assertEqual(repr(qs[1]), '') + self.assertEqual( + repr(qs[1]), + '', + ) def test_fix_getattribute(self): # fixed issue in PolymorphicModel.__getattribute__: field name same as model name - o = ModelFieldNameTest.objects.create(modelfieldnametest='1') - self.assertEqual(repr(o), '') + o = ModelFieldNameTest.objects.create(modelfieldnametest="1") + self.assertEqual( + repr(o), "" + ) # if subclass defined __init__ and accessed class members, # __getattribute__ had a problem: "...has no attribute 'sub_and_superclass_dict'" o = InitTestModelSubclass.objects.create() - self.assertEqual(o.bar, 'XYZ') + self.assertEqual(o.bar, "XYZ") def test_parent_link_and_related_name(self): t = TestParentLinkAndRelatedName(field1="TestParentLinkAndRelatedName") @@ -940,8 +1046,12 @@ class PolymorphicTests(TransactionTestCase): self.assertEqual(p, t) # check that the accessors to parent and sublass work correctly and return the right object - p = ModelShow1_plain.objects.non_polymorphic().get(field1="TestParentLinkAndRelatedName") - self.assertNotEqual(p, t) # p should be Plain1 and t TestParentLinkAndRelatedName, so not equal + p = ModelShow1_plain.objects.non_polymorphic().get( + field1="TestParentLinkAndRelatedName" + ) + self.assertNotEqual( + p, t + ) # p should be Plain1 and t TestParentLinkAndRelatedName, so not equal self.assertEqual(p, t.superclass) self.assertEqual(p.related_name_subclass, t) @@ -951,59 +1061,62 @@ class PolymorphicTests(TransactionTestCase): def test_polymorphic__aggregate(self): """ test ModelX___field syntax on aggregate (should work for annotate either) """ - Model2A.objects.create(field1='A1') - Model2B.objects.create(field1='A1', field2='B2') - Model2B.objects.create(field1='A1', field2='B2') + Model2A.objects.create(field1="A1") + Model2B.objects.create(field1="A1", field2="B2") + Model2B.objects.create(field1="A1", field2="B2") # aggregate using **kwargs - result = Model2A.objects.aggregate(cnt=Count('Model2B___field2')) - self.assertEqual(result, {'cnt': 2}) + result = Model2A.objects.aggregate(cnt=Count("Model2B___field2")) + self.assertEqual(result, {"cnt": 2}) # aggregate using **args self.assertRaisesMessage( AssertionError, - 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only', - lambda: Model2A.objects.aggregate(Count('Model2B___field2')) + "PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only", + lambda: Model2A.objects.aggregate(Count("Model2B___field2")), ) def test_polymorphic__complex_aggregate(self): """ test (complex expression on) aggregate (should work for annotate either) """ - Model2A.objects.create(field1='A1') - Model2B.objects.create(field1='A1', field2='B2') - Model2B.objects.create(field1='A1', field2='B2') + Model2A.objects.create(field1="A1") + Model2B.objects.create(field1="A1", field2="B2") + Model2B.objects.create(field1="A1", field2="B2") # aggregate using **kwargs result = Model2A.objects.aggregate( - cnt_a1=Count(Case(When(field1='A1', then=1))), - cnt_b2=Count(Case(When(Model2B___field2='B2', then=1))), + cnt_a1=Count(Case(When(field1="A1", then=1))), + cnt_b2=Count(Case(When(Model2B___field2="B2", then=1))), ) - self.assertEqual(result, {'cnt_b2': 2, 'cnt_a1': 3}) + self.assertEqual(result, {"cnt_b2": 2, "cnt_a1": 3}) # aggregate using **args # we have to set the defaul alias or django won't except a complex expression # on aggregate/annotate def ComplexAgg(expression): complexagg = Count(expression) * 10 - complexagg.default_alias = 'complexagg' + complexagg.default_alias = "complexagg" return complexagg - with self.assertRaisesMessage(AssertionError, 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only'): - Model2A.objects.aggregate(ComplexAgg('Model2B___field2')) + with self.assertRaisesMessage( + AssertionError, + "PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only", + ): + Model2A.objects.aggregate(ComplexAgg("Model2B___field2")) def test_polymorphic__expressions(self): from django.db.models.functions import Concat # no exception raised - result = Model2B.objects.annotate(val=Concat('field1', 'field2')) + result = Model2B.objects.annotate(val=Concat("field1", "field2")) self.assertEqual(list(result), []) def test_null_polymorphic_id(self): """Test that a proper error message is displayed when the database lacks the ``polymorphic_ctype_id``""" - Model2A.objects.create(field1='A1') - Model2B.objects.create(field1='A1', field2='B2') - Model2B.objects.create(field1='A1', field2='B2') + Model2A.objects.create(field1="A1") + Model2B.objects.create(field1="A1", field2="B2") + Model2B.objects.create(field1="A1", field2="B2") Model2A.objects.all().update(polymorphic_ctype_id=None) with self.assertRaises(PolymorphicTypeUndefined): @@ -1011,9 +1124,9 @@ class PolymorphicTests(TransactionTestCase): def test_invalid_polymorphic_id(self): """Test that a proper error message is displayed when the database ``polymorphic_ctype_id`` is invalid""" - Model2A.objects.create(field1='A1') - Model2B.objects.create(field1='A1', field2='B2') - Model2B.objects.create(field1='A1', field2='B2') + Model2A.objects.create(field1="A1") + Model2B.objects.create(field1="A1", field2="B2") + Model2B.objects.create(field1="A1", field2="B2") invalid = ContentType.objects.get_for_model(PlainA).pk Model2A.objects.all().update(polymorphic_ctype_id=invalid) @@ -1021,59 +1134,72 @@ class PolymorphicTests(TransactionTestCase): list(Model2A.objects.all()) def test_bulk_create_abstract_inheritance(self): - ArtProject.objects.bulk_create([ - ArtProject(topic='Painting with Tim', artist='T. Turner'), - ArtProject(topic='Sculpture with Tim', artist='T. Turner'), - ]) + ArtProject.objects.bulk_create( + [ + ArtProject(topic="Painting with Tim", artist="T. Turner"), + ArtProject(topic="Sculpture with Tim", artist="T. Turner"), + ] + ) self.assertEqual( - sorted(ArtProject.objects.values_list('topic', 'artist')), - [('Painting with Tim', 'T. Turner'), ('Sculpture with Tim', 'T. Turner')] + sorted(ArtProject.objects.values_list("topic", "artist")), + [("Painting with Tim", "T. Turner"), ("Sculpture with Tim", "T. Turner")], ) def test_bulk_create_proxy_inheritance(self): - RedheadDuck.objects.bulk_create([ - RedheadDuck(name='redheadduck1'), - Duck(name='duck1'), - RubberDuck(name='rubberduck1'), - ]) - RubberDuck.objects.bulk_create([ - RedheadDuck(name='redheadduck2'), - RubberDuck(name='rubberduck2'), - Duck(name='duck2'), - ]) - self.assertEqual( - sorted(RedheadDuck.objects.values_list('name', flat=True)), - ['redheadduck1', 'redheadduck2'], + RedheadDuck.objects.bulk_create( + [ + RedheadDuck(name="redheadduck1"), + Duck(name="duck1"), + RubberDuck(name="rubberduck1"), + ] + ) + RubberDuck.objects.bulk_create( + [ + RedheadDuck(name="redheadduck2"), + RubberDuck(name="rubberduck2"), + Duck(name="duck2"), + ] ) self.assertEqual( - sorted(RubberDuck.objects.values_list('name', flat=True)), - ['rubberduck1', 'rubberduck2'], + sorted(RedheadDuck.objects.values_list("name", flat=True)), + ["redheadduck1", "redheadduck2"], ) self.assertEqual( - sorted(Duck.objects.values_list('name', flat=True)), - ['duck1', 'duck2', 'redheadduck1', 'redheadduck2', 'rubberduck1', 'rubberduck2'], + sorted(RubberDuck.objects.values_list("name", flat=True)), + ["rubberduck1", "rubberduck2"], + ) + self.assertEqual( + sorted(Duck.objects.values_list("name", flat=True)), + [ + "duck1", + "duck2", + "redheadduck1", + "redheadduck2", + "rubberduck1", + "rubberduck2", + ], ) def test_bulk_create_unsupported_multi_table_inheritance(self): with self.assertRaises(ValueError): - MultiTableDerived.objects.bulk_create([ - MultiTableDerived(field1='field1', field2='field2') - ]) + MultiTableDerived.objects.bulk_create( + [MultiTableDerived(field1="field1", field2="field2")] + ) def test_can_query_using_subclass_selector_on_abstract_model(self): - obj = SubclassSelectorAbstractConcreteModel.objects.create(concrete_field='abc') + obj = SubclassSelectorAbstractConcreteModel.objects.create(concrete_field="abc") queried_obj = SubclassSelectorAbstractBaseModel.objects.filter( - SubclassSelectorAbstractConcreteModel___concrete_field='abc' + SubclassSelectorAbstractConcreteModel___concrete_field="abc" ).get() self.assertEqual(obj.pk, queried_obj.pk) def test_can_query_using_subclass_selector_on_proxy_model(self): - obj = SubclassSelectorProxyConcreteModel.objects.create(concrete_field='abc') + obj = SubclassSelectorProxyConcreteModel.objects.create(concrete_field="abc") queried_obj = SubclassSelectorProxyBaseModel.objects.filter( - SubclassSelectorProxyConcreteModel___concrete_field='abc' + SubclassSelectorProxyConcreteModel___concrete_field="abc" ).get() self.assertEqual(obj.pk, queried_obj.pk) @@ -1083,7 +1209,7 @@ class PolymorphicTests(TransactionTestCase): b2 = RelatingModel.objects.create() a = b1.many2many.create() # create Model2A b2.many2many.add(a) # add same to second relating model - qs = RelatingModel.objects.prefetch_related('many2many') + qs = RelatingModel.objects.prefetch_related("many2many") for obj in qs: self.assertEqual(len(obj.many2many.all()), 1) @@ -1091,16 +1217,20 @@ class PolymorphicTests(TransactionTestCase): b1 = RelatingModel.objects.create() b2 = RelatingModel.objects.create() - rel1 = Model2A.objects.create(field1='A1') - rel2 = Model2B.objects.create(field1='A2', field2='B2') + rel1 = Model2A.objects.create(field1="A1") + rel2 = Model2B.objects.create(field1="A2", field2="B2") b1.many2many.add(rel1) b2.many2many.add(rel2) rel2.delete(keep_parents=True) - qs = RelatingModel.objects.order_by('pk').prefetch_related('many2many') + qs = RelatingModel.objects.order_by("pk").prefetch_related("many2many") objects = list(qs) self.assertEqual(len(objects[0].many2many.all()), 1) - self.assertEqual(len(objects[1].many2many.all()), 0) # derived object was not fetched - self.assertEqual(len(objects[1].many2many.non_polymorphic()), 1) # base object does exist + self.assertEqual( + len(objects[1].many2many.all()), 0 + ) # derived object was not fetched + self.assertEqual( + len(objects[1].many2many.non_polymorphic()), 1 + ) # base object does exist diff --git a/polymorphic/tests/test_regression.py b/polymorphic/tests/test_regression.py index 073992a..f008bee 100644 --- a/polymorphic/tests/test_regression.py +++ b/polymorphic/tests/test_regression.py @@ -1,9 +1,9 @@ from django.test import TestCase + from polymorphic.tests.models import Bottom, Middle, Top class RegressionTests(TestCase): - def test_for_query_result_incomplete_with_inheritance(self): """ https://github.com/bconstantin/django_polymorphic/issues/15 """ @@ -15,10 +15,16 @@ class RegressionTests(TestCase): bottom.save() expected_queryset = [top, middle, bottom] - self.assertQuerysetEqual(Top.objects.order_by('pk'), [repr(r) for r in expected_queryset]) + self.assertQuerysetEqual( + Top.objects.order_by("pk"), [repr(r) for r in expected_queryset] + ) expected_queryset = [middle, bottom] - self.assertQuerysetEqual(Middle.objects.order_by('pk'), [repr(r) for r in expected_queryset]) + self.assertQuerysetEqual( + Middle.objects.order_by("pk"), [repr(r) for r in expected_queryset] + ) expected_queryset = [bottom] - self.assertQuerysetEqual(Bottom.objects.order_by('pk'), [repr(r) for r in expected_queryset]) + self.assertQuerysetEqual( + Bottom.objects.order_by("pk"), [repr(r) for r in expected_queryset] + ) diff --git a/polymorphic/tests/test_utils.py b/polymorphic/tests/test_utils.py index fffd2fc..9aea271 100644 --- a/polymorphic/tests/test_utils.py +++ b/polymorphic/tests/test_utils.py @@ -1,26 +1,36 @@ from django.test import TransactionTestCase -from polymorphic.models import PolymorphicTypeUndefined, PolymorphicModel -from polymorphic.tests.models import Model2A, Model2B, Model2C, Model2D, Enhance_Inherit, Enhance_Base -from polymorphic.utils import reset_polymorphic_ctype, sort_by_subclass, get_base_polymorphic_model +from polymorphic.models import PolymorphicModel, PolymorphicTypeUndefined +from polymorphic.tests.models import ( + Enhance_Base, + Enhance_Inherit, + Model2A, + Model2B, + Model2C, + Model2D, +) +from polymorphic.utils import ( + get_base_polymorphic_model, + reset_polymorphic_ctype, + sort_by_subclass, +) class UtilsTests(TransactionTestCase): - def test_sort_by_subclass(self): self.assertEqual( sort_by_subclass(Model2D, Model2B, Model2D, Model2A, Model2C), - [Model2A, Model2B, Model2C, Model2D, Model2D] + [Model2A, Model2B, Model2C, Model2D, Model2D], ) def test_reset_polymorphic_ctype(self): """ Test the the polymorphic_ctype_id can be restored. """ - Model2A.objects.create(field1='A1') - Model2D.objects.create(field1='A1', field2='B2', field3='C3', field4='D4') - Model2B.objects.create(field1='A1', field2='B2') - Model2B.objects.create(field1='A1', field2='B2') + Model2A.objects.create(field1="A1") + Model2D.objects.create(field1="A1", field2="B2", field3="C3", field4="D4") + Model2B.objects.create(field1="A1", field2="B2") + Model2B.objects.create(field1="A1", field2="B2") Model2A.objects.all().update(polymorphic_ctype_id=None) with self.assertRaises(PolymorphicTypeUndefined): @@ -30,12 +40,7 @@ class UtilsTests(TransactionTestCase): self.assertQuerysetEqual( Model2A.objects.order_by("pk"), - [ - Model2A, - Model2D, - Model2B, - Model2B, - ], + [Model2A, Model2D, Model2B, Model2B], transform=lambda o: o.__class__, ) @@ -59,6 +64,7 @@ class UtilsTests(TransactionTestCase): """ Skipping abstract models that can't be used for querying. """ + class A(PolymorphicModel): class Meta: abstract = True diff --git a/polymorphic/utils.py b/polymorphic/utils.py index 956bc46..14c9a9f 100644 --- a/polymorphic/utils.py +++ b/polymorphic/utils.py @@ -2,9 +2,9 @@ import sys from django.contrib.contenttypes.models import ContentType from django.db import DEFAULT_DB_ALIAS -from polymorphic.models import PolymorphicModel from polymorphic.base import PolymorphicModelBase +from polymorphic.models import PolymorphicModel def reset_polymorphic_ctype(*models, **filters): @@ -16,8 +16,8 @@ def reset_polymorphic_ctype(*models, **filters): Add ``preserve_existing=True`` to skip models which already have a polymorphic content type. """ - using = filters.pop('using', DEFAULT_DB_ALIAS) - ignore_existing = filters.pop('ignore_existing', False) + using = filters.pop("using", DEFAULT_DB_ALIAS) + ignore_existing = filters.pop("ignore_existing", False) models = sort_by_subclass(*models) if ignore_existing: @@ -26,7 +26,9 @@ def reset_polymorphic_ctype(*models, **filters): models = reversed(models) for new_model in models: - new_ct = ContentType.objects.db_manager(using).get_for_model(new_model, for_concrete_model=False) + new_ct = ContentType.objects.db_manager(using).get_for_model( + new_model, for_concrete_model=False + ) qs = new_model.objects.db_manager(using) if ignore_existing: @@ -61,6 +63,7 @@ def sort_by_subclass(*classes): return sorted(classes, cmp=_compare_mro) else: from functools import cmp_to_key + return sorted(classes, key=cmp_to_key(_compare_mro)) @@ -69,8 +72,10 @@ def get_base_polymorphic_model(ChildModel, allow_abstract=False): First the first concrete model in the inheritance chain that inherited from the PolymorphicModel. """ for Model in reversed(ChildModel.mro()): - if isinstance(Model, PolymorphicModelBase) and \ - Model is not PolymorphicModel and \ - (allow_abstract or not Model._meta.abstract): + if ( + isinstance(Model, PolymorphicModelBase) + and Model is not PolymorphicModel + and (allow_abstract or not Model._meta.abstract) + ): return Model return None diff --git a/runtests.py b/runtests.py index 7ae62f9..75a7253 100755 --- a/runtests.py +++ b/runtests.py @@ -8,85 +8,87 @@ import django from django.conf import settings from django.core.management import execute_from_command_line - # python -Wd, or run via coverage: -warnings.simplefilter('always', DeprecationWarning) +warnings.simplefilter("always", DeprecationWarning) # Give feedback on used versions -sys.stderr.write('Using Python version {0} from {1}\n'.format(sys.version[:5], sys.executable)) -sys.stderr.write('Using Django version {0} from {1}\n'.format( - django.get_version(), - dirname(abspath(django.__file__))) +sys.stderr.write( + "Using Python version {0} from {1}\n".format(sys.version[:5], sys.executable) +) +sys.stderr.write( + "Using Django version {0} from {1}\n".format( + django.get_version(), dirname(abspath(django.__file__)) + ) ) if not settings.configured: settings.configure( DEBUG=False, DATABASES={ - 'default': dj_database_url.config( - env='PRIMARY_DATABASE', - default='sqlite://:memory:', + "default": dj_database_url.config( + env="PRIMARY_DATABASE", default="sqlite://:memory:" ), - 'secondary': dj_database_url.config( - env='SECONDARY_DATABASE', - default='sqlite://:memory:', + "secondary": dj_database_url.config( + env="SECONDARY_DATABASE", default="sqlite://:memory:" ), }, TEST_RUNNER="django.test.runner.DiscoverRunner", INSTALLED_APPS=( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.messages', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.admin', - 'polymorphic', - 'polymorphic.tests', + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.messages", + "django.contrib.sessions", + "django.contrib.sites", + "django.contrib.admin", + "polymorphic", + "polymorphic.tests", ), - MIDDLEWARE = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', + MIDDLEWARE=( + "django.middleware.common.CommonMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", ), SITE_ID=3, - TEMPLATES=[{ - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": (), - "OPTIONS": { - "loaders": ( - "django.template.loaders.filesystem.Loader", - "django.template.loaders.app_directories.Loader", - ), - "context_processors": ( - "django.template.context_processors.debug", - "django.template.context_processors.i18n", - "django.template.context_processors.media", - "django.template.context_processors.request", - "django.template.context_processors.static", - "django.contrib.messages.context_processors.messages", - "django.contrib.auth.context_processors.auth", - ), - }, - }, + TEMPLATES=[ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": (), + "OPTIONS": { + "loaders": ( + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + ), + "context_processors": ( + "django.template.context_processors.debug", + "django.template.context_processors.i18n", + "django.template.context_processors.media", + "django.template.context_processors.request", + "django.template.context_processors.static", + "django.contrib.messages.context_processors.messages", + "django.contrib.auth.context_processors.auth", + ), + }, + } ], - POLYMORPHIC_TEST_SWAPPABLE='polymorphic.swappedmodel', + POLYMORPHIC_TEST_SWAPPABLE="polymorphic.swappedmodel", ROOT_URLCONF=None, ) -DEFAULT_TEST_APPS = [ - 'polymorphic', -] +DEFAULT_TEST_APPS = ["polymorphic"] def runtests(): - other_args = list(filter(lambda arg: arg.startswith('-'), sys.argv[1:])) - test_apps = list(filter(lambda arg: not arg.startswith('-'), sys.argv[1:])) or DEFAULT_TEST_APPS - argv = sys.argv[:1] + ['test', '--traceback'] + other_args + test_apps + other_args = list(filter(lambda arg: arg.startswith("-"), sys.argv[1:])) + test_apps = ( + list(filter(lambda arg: not arg.startswith("-"), sys.argv[1:])) + or DEFAULT_TEST_APPS + ) + argv = sys.argv[:1] + ["test", "--traceback"] + other_args + test_apps execute_from_command_line(argv) -if __name__ == '__main__': +if __name__ == "__main__": runtests() diff --git a/setup.py b/setup.py index dd4e63e..beda28e 100755 --- a/setup.py +++ b/setup.py @@ -2,5 +2,4 @@ from setuptools import setup - setup()