diff --git a/python/pluginCore/resources/META-INF/plugin.xml b/python/pluginCore/resources/META-INF/plugin.xml
index 6cab36e08014..0012357cad63 100644
--- a/python/pluginCore/resources/META-INF/plugin.xml
+++ b/python/pluginCore/resources/META-INF/plugin.xml
@@ -203,6 +203,14 @@ The Python plug-in provides smart editing for Python scripts. The feature set of
serviceImplementation="com.jetbrains.python.run.PyRunConfigurationFactoryImpl"/>
+
+
+
+
+
+
+
+
diff --git a/python/pluginResources/messages/PyBundle.properties b/python/pluginResources/messages/PyBundle.properties
index 9360f6503a9f..6fb7336d0c70 100644
--- a/python/pluginResources/messages/PyBundle.properties
+++ b/python/pluginResources/messages/PyBundle.properties
@@ -1144,6 +1144,13 @@ python.run.configuration.fragments.plugin.sdk.of.module=Use SDK of module
python.run.configuration.fragments.plugin.sdk.of.module.hint=Select module
python.run.configuration.fragments.plugin.specified.interpreter=Use specified interpreter
python.run.configuration.fragments.plugin.specified.interpreter.hint=Select Python interpreter
+
+# well-known pro-configurations to gracefully show
+python.run.configuration.django.name=Django server
+python.run.configuration.is.not.editable.in.this.mode=This run configuration is unavailable in the free mode and cannot be edited.
+python.run.configuration.is.not.runnable.in.this.mode=This run configuration is unavailable in the free mode and cannot be run.
+
+
# Python reStructuredText forms
rest.configuration.editor.open.output.file.in.browser.label.text=Open output file in browser
sphinx.ask.for.working.directory.label.text=Sphinx working directory
diff --git a/python/src/com/jetbrains/python/run/PythonLockedRunConfiguration.kt b/python/src/com/jetbrains/python/run/PythonLockedRunConfiguration.kt
new file mode 100644
index 000000000000..d4b128700a0b
--- /dev/null
+++ b/python/src/com/jetbrains/python/run/PythonLockedRunConfiguration.kt
@@ -0,0 +1,166 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.jetbrains.python.run
+
+// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+
+import com.intellij.execution.ExecutionException
+import com.intellij.execution.Executor
+import com.intellij.execution.configurations.*
+import com.intellij.execution.runners.ExecutionEnvironment
+import com.intellij.execution.runners.RunConfigurationWithSuppressedDefaultRunAction
+import com.intellij.icons.AllIcons
+import com.intellij.openapi.options.SettingsEditor
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.JDOMUtil
+import com.intellij.openapi.util.NlsSafe
+import com.intellij.openapi.util.WriteExternalException
+import com.intellij.ui.dsl.builder.AlignX
+import com.intellij.ui.dsl.builder.panel
+import com.jetbrains.python.PyBundle
+import org.jdom.Element
+import org.jetbrains.annotations.Nls
+import org.jetbrains.annotations.NonNls
+import java.util.concurrent.atomic.AtomicInteger
+import javax.swing.Icon
+import javax.swing.JComponent
+
+private class PythonLockedRunConfigurationEditor : SettingsEditor() {
+
+ override fun resetEditorFrom(s: PythonLockedRunConfiguration) {}
+
+ override fun applyEditorTo(s: PythonLockedRunConfiguration) {}
+
+ protected override fun createEditor(): JComponent = panel {
+ row {
+ label(PyBundle.message("python.run.configuration.is.not.editable.in.this.mode")).align(AlignX.CENTER)
+ }
+ }
+}
+
+private class PythonLockedRunConfiguration(val configProject: Project, val configFactory: ConfigurationFactory)
+ : RunConfiguration, WithoutOwnBeforeRunSteps, RunConfigurationWithSuppressedDefaultRunAction {
+
+ var theName: String? = null
+ var configElement: Element? = null
+
+ override fun getFactory(): ConfigurationFactory? {
+ return configFactory
+ }
+
+ override fun getConfigurationEditor(): SettingsEditor {
+ return PythonLockedRunConfigurationEditor()
+ }
+
+ override fun getProject(): Project? {
+ return configProject
+ }
+
+ override fun clone(): RunConfiguration {
+ return PythonLockedRunConfiguration(configProject, configFactory)
+ }
+
+ override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState? {
+ throw ExecutionException(PyBundle.message("python.run.configuration.is.not.runnable.in.this.mode"))
+ }
+
+ override fun checkConfiguration() {
+ throw RuntimeConfigurationWarning(PyBundle.message("python.run.configuration.is.not.runnable.in.this.mode"))
+ }
+
+ override fun setName(value: String) {
+ theName = value
+ }
+
+ override fun getName(): @NlsSafe String {
+ return tryGetName() ?: "LockedConfiguration${nameCounter.getAndIncrement()}"
+ }
+
+ override fun getIcon(): Icon? {
+ return configFactory.icon
+ }
+
+ override fun readExternal(element: Element) {
+ configElement = JDOMUtil.internElement(element)
+ }
+
+ @Throws(WriteExternalException::class)
+ override fun writeExternal(element: Element) {
+ val data = configElement ?: return
+
+ for (a in data.getAttributes()) {
+ element.setAttribute(a.name, a.value)
+ }
+
+ for (child in data.children) {
+ element.addContent(child.clone())
+ }
+ }
+
+ private fun tryGetName(): @NlsSafe String? {
+ val name = theName
+ if (name != null) {
+ return name
+ }
+
+ val data = configElement ?: return null
+ return data.getAttributeValue("name")
+ }
+
+ companion object {
+ var nameCounter = AtomicInteger(1)
+ }
+}
+
+private class PythonLockedRunConfigurationFactory(type: ConfigurationType)
+ : ConfigurationFactory(type) {
+ override fun getId(): String {
+ return name
+ }
+
+ override fun createTemplateConfiguration(project: Project): RunConfiguration {
+ return PythonLockedRunConfiguration(project, this)
+ }
+}
+
+private open class PythonLockedRunConfigurationTypeBase(val theId: String, @Nls val name: String)
+ : ConfigurationType {
+ private val factory: ConfigurationFactory = PythonLockedRunConfigurationFactory(this)
+
+ override fun getDisplayName(): @Nls(capitalization = Nls.Capitalization.Title) String {
+ return name
+ }
+
+ override fun getConfigurationTypeDescription(): @Nls(capitalization = Nls.Capitalization.Sentence) String? {
+ return name
+ }
+
+ override fun getIcon(): Icon? {
+ return AllIcons.Ultimate.PycharmLock
+ }
+
+ override fun getId(): @NonNls String {
+ return theId
+ }
+
+ override fun getConfigurationFactories(): Array? {
+ return arrayOf(factory)
+ }
+
+ override fun isDumbAware(): Boolean {
+ return true
+ }
+
+ override fun isManaged(): Boolean {
+ return false
+ }
+}
+
+
+private class DjangoServerLockedRunConfigurationType : PythonLockedRunConfigurationTypeBase("Python.DjangoServer", PyBundle.message("python.run.configuration.django.name"))
+private class FlaskServerLockedRunConfigurationType : PythonLockedRunConfigurationTypeBase("Python.FlaskServer", PyBundle.message("flask.name"))
+private class DbtRunLockedConfigurationType : PythonLockedRunConfigurationTypeBase("DbtRunConfiguration", "dbt")
+private class FastAPILockedRunConfigurationType : PythonLockedRunConfigurationTypeBase("Python.FastAPI", "FastAPI")
+
+//private class DjangoFacetIgnorer : FacetIgnorer {
+// override fun isIgnored(facet: InvalidFacet): Boolean = facet.name == "Django"
+//}
\ No newline at end of file