mirror of
https://github.com/django/django.git
synced 2025-07-05 10:19:20 +00:00
magic-removal: Removed app-specific stuff from django.core.management.syncdb, in favor of an event-based system. Permissions, superusers and the example.com site are now all done via a management.py file within the appropriate contrib app. This also means 'createsuperuser' is no longer a django-admin command...We'll probably want to restore that somehow, or add another utility that does it from the command line.
git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2551 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
17a4401f4c
commit
cb5e2764be
84
django/contrib/auth/create_superuser.py
Normal file
84
django/contrib/auth/create_superuser.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
"""
|
||||||
|
Helper function for creating superusers in the authentication system.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.core import validators
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def createsuperuser(username=None, email=None, password=None):
|
||||||
|
"""
|
||||||
|
Helper function for creating a superuser from the command line. All
|
||||||
|
arguments are optional and will be prompted-for if invalid or not given.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
import pwd
|
||||||
|
except ImportError:
|
||||||
|
default_username = ''
|
||||||
|
else:
|
||||||
|
# Determine the current system user's username, to use as a default.
|
||||||
|
default_username = pwd.getpwuid(os.getuid())[0].replace(' ', '').lower()
|
||||||
|
|
||||||
|
# Determine whether the default username is taken, so we don't display
|
||||||
|
# it as an option.
|
||||||
|
if default_username:
|
||||||
|
try:
|
||||||
|
User.objects.get(username=default_username)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
default_username = ''
|
||||||
|
|
||||||
|
try:
|
||||||
|
while 1:
|
||||||
|
if not username:
|
||||||
|
input_msg = 'Username'
|
||||||
|
if default_username:
|
||||||
|
input_msg += ' (Leave blank to use %r)' % default_username
|
||||||
|
username = raw_input(input_msg + ': ')
|
||||||
|
if default_username and username == '':
|
||||||
|
username = default_username
|
||||||
|
if not username.isalnum():
|
||||||
|
sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
|
||||||
|
username = None
|
||||||
|
try:
|
||||||
|
User.objects.get(username=username)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
sys.stderr.write("Error: That username is already taken.\n")
|
||||||
|
username = None
|
||||||
|
while 1:
|
||||||
|
if not email:
|
||||||
|
email = raw_input('E-mail address: ')
|
||||||
|
try:
|
||||||
|
validators.isValidEmail(email, None)
|
||||||
|
except validators.ValidationError:
|
||||||
|
sys.stderr.write("Error: That e-mail address is invalid.\n")
|
||||||
|
email = None
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
while 1:
|
||||||
|
if not password:
|
||||||
|
password = getpass.getpass()
|
||||||
|
password2 = getpass.getpass('Password (again): ')
|
||||||
|
if password != password2:
|
||||||
|
sys.stderr.write("Error: Your passwords didn't match.\n")
|
||||||
|
password = None
|
||||||
|
continue
|
||||||
|
if password.strip() == '':
|
||||||
|
sys.stderr.write("Error: Blank passwords aren't allowed.\n")
|
||||||
|
password = None
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.stderr.write("\nOperation cancelled.\n")
|
||||||
|
sys.exit(1)
|
||||||
|
u = User.objects.create_user(username, email, password)
|
||||||
|
u.is_staff = True
|
||||||
|
u.is_active = True
|
||||||
|
u.is_superuser = True
|
||||||
|
u.save()
|
||||||
|
print "Superuser created successfully."
|
53
django/contrib/auth/management.py
Normal file
53
django/contrib/auth/management.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
"""
|
||||||
|
Creates permissions for all installed apps that need permissions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.dispatch import dispatcher
|
||||||
|
from django.db.models import get_models, signals
|
||||||
|
from django.contrib.auth import models as auth_app
|
||||||
|
|
||||||
|
def _get_permission_codename(action, opts):
|
||||||
|
return '%s_%s' % (action, opts.object_name.lower())
|
||||||
|
|
||||||
|
def _get_all_permissions(opts):
|
||||||
|
"Returns (codename, name) for all permissions in the given opts."
|
||||||
|
perms = []
|
||||||
|
for action in ('add', 'change', 'delete'):
|
||||||
|
perms.append((_get_permission_codename(action, opts), 'Can %s %s' % (action, opts.verbose_name)))
|
||||||
|
return perms + list(opts.permissions)
|
||||||
|
|
||||||
|
def create_permissions(app, created_models):
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.contrib.auth.models import Permission
|
||||||
|
app_models = get_models(app)
|
||||||
|
if not app_models:
|
||||||
|
return
|
||||||
|
for klass in app_models:
|
||||||
|
if not klass._meta.admin:
|
||||||
|
continue
|
||||||
|
ctype = ContentType.objects.get_for_model(klass)
|
||||||
|
for codename, name in _get_all_permissions(klass._meta):
|
||||||
|
try:
|
||||||
|
Permission.objects.get(name=name, codename=codename, content_type__pk=ctype.id)
|
||||||
|
except Permission.DoesNotExist:
|
||||||
|
p = Permission(name=name, codename=codename, content_type=ctype)
|
||||||
|
p.save()
|
||||||
|
print "Adding permission '%r'" % p
|
||||||
|
|
||||||
|
def create_superuser(app, created_models):
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.contrib.auth.create_superuser import createsuperuser as do_create
|
||||||
|
if User in created_models:
|
||||||
|
msg = "\nYou just installed Django's auth system, which means you don't have " \
|
||||||
|
"any superusers defined.\nWould you like to create one now? (yes/no): "
|
||||||
|
confirm = raw_input(msg)
|
||||||
|
while 1:
|
||||||
|
if confirm not in ('yes', 'no'):
|
||||||
|
confirm = raw_input('Please enter either "yes" or "no": ')
|
||||||
|
continue
|
||||||
|
if confirm == 'yes':
|
||||||
|
do_create()
|
||||||
|
break
|
||||||
|
|
||||||
|
dispatcher.connect(create_permissions, signal=signals.post_syncdb)
|
||||||
|
dispatcher.connect(create_superuser, sender=auth_app, signal=signals.post_syncdb)
|
16
django/contrib/sites/management.py
Normal file
16
django/contrib/sites/management.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
Creates the default Site object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.dispatch import dispatcher
|
||||||
|
from django.db.models import signals
|
||||||
|
from django.contrib.sites.models import Site
|
||||||
|
from django.contrib.sites import models as site_app
|
||||||
|
|
||||||
|
def create_default_site(app, created_models):
|
||||||
|
if Site in created_models:
|
||||||
|
print "Creating example.com Site object"
|
||||||
|
s = Site(domain="example.com", name="example.com")
|
||||||
|
s.save()
|
||||||
|
|
||||||
|
dispatcher.connect(create_default_site, sender=site_app, signal=signals.post_syncdb)
|
@ -26,23 +26,6 @@ PROJECT_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf', '%s_template')
|
|||||||
|
|
||||||
INVALID_PROJECT_NAMES = ('django', 'test')
|
INVALID_PROJECT_NAMES = ('django', 'test')
|
||||||
|
|
||||||
def _get_permission_codename(action, opts):
|
|
||||||
return '%s_%s' % (action, opts.object_name.lower())
|
|
||||||
|
|
||||||
def _get_all_permissions(opts):
|
|
||||||
"Returns (codename, name) for all permissions in the given opts."
|
|
||||||
perms = []
|
|
||||||
if opts.admin:
|
|
||||||
for action in ('add', 'change', 'delete'):
|
|
||||||
perms.append((_get_permission_codename(action, opts), 'Can %s %s' % (action, opts.verbose_name)))
|
|
||||||
return perms + list(opts.permissions)
|
|
||||||
|
|
||||||
def _get_permission_insert(name, codename, opts):
|
|
||||||
from django.db import backend
|
|
||||||
return "INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s');" % \
|
|
||||||
(backend.quote_name('auth_permission'), backend.quote_name('name'), backend.quote_name('package'),
|
|
||||||
backend.quote_name('codename'), name.replace("'", "''"), opts.app_label, codename)
|
|
||||||
|
|
||||||
def _is_valid_dir_name(s):
|
def _is_valid_dir_name(s):
|
||||||
return bool(re.search(r'^\w+$', s))
|
return bool(re.search(r'^\w+$', s))
|
||||||
|
|
||||||
@ -398,10 +381,21 @@ get_sql_all.args = APP_ARGS
|
|||||||
def syncdb():
|
def syncdb():
|
||||||
"Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
|
"Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
|
||||||
from django.db import connection, transaction, models, get_creation_module
|
from django.db import connection, transaction, models, get_creation_module
|
||||||
|
from django.db.models import signals
|
||||||
|
from django.conf import settings
|
||||||
|
from django.dispatch import dispatcher
|
||||||
|
|
||||||
# Check that there are no validation errors before continuing
|
# Check that there are no validation errors before continuing
|
||||||
_check_for_validation_errors()
|
_check_for_validation_errors()
|
||||||
|
|
||||||
|
# Import the 'management' module within each installed app, to register
|
||||||
|
# dispatcher events.
|
||||||
|
for app_name in settings.INSTALLED_APPS:
|
||||||
|
try:
|
||||||
|
__import__(app_name + '.management', '', '', [''])
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
data_types = get_creation_module().DATA_TYPES
|
data_types = get_creation_module().DATA_TYPES
|
||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
@ -414,7 +408,6 @@ def syncdb():
|
|||||||
seen_models = _get_installed_models(table_list)
|
seen_models = _get_installed_models(table_list)
|
||||||
created_models = set()
|
created_models = set()
|
||||||
pending_references = {}
|
pending_references = {}
|
||||||
install_permissions = True
|
|
||||||
|
|
||||||
for app in models.get_apps():
|
for app in models.get_apps():
|
||||||
model_list = models.get_models(app)
|
model_list = models.get_models(app)
|
||||||
@ -441,21 +434,11 @@ def syncdb():
|
|||||||
|
|
||||||
transaction.commit_unless_managed()
|
transaction.commit_unless_managed()
|
||||||
|
|
||||||
# Install permissions and initial data (first checking that they're installed)
|
# Send the post_syncdb signal, so individual apps can do whatever they need
|
||||||
|
# to do at this point.
|
||||||
for app in models.get_apps():
|
for app in models.get_apps():
|
||||||
if install_permissions:
|
dispatcher.send(signal=signals.post_syncdb, sender=app,
|
||||||
try:
|
app=app, created_models=created_models)
|
||||||
installperms(app)
|
|
||||||
except Exception, e:
|
|
||||||
# stop trying to install permissions
|
|
||||||
install_permissions = False
|
|
||||||
sys.stderr.write("Permissions will not be installed because it "\
|
|
||||||
"appears that you are not using Django's auth framework. "\
|
|
||||||
"If you want to install them in the future, re-run syncdb."\
|
|
||||||
"\n(The full error was: %s)\n" % e)
|
|
||||||
transaction.rollback_unless_managed()
|
|
||||||
else:
|
|
||||||
transaction.commit_unless_managed()
|
|
||||||
|
|
||||||
# Install initial data for the app (but only if this is a model we've
|
# Install initial data for the app (but only if this is a model we've
|
||||||
# just created)
|
# just created)
|
||||||
@ -474,27 +457,6 @@ def syncdb():
|
|||||||
else:
|
else:
|
||||||
transaction.commit_unless_managed()
|
transaction.commit_unless_managed()
|
||||||
|
|
||||||
# Create an initial "example.com" site (if we need to)
|
|
||||||
from django.contrib.sites.models import Site
|
|
||||||
if Site in created_models:
|
|
||||||
print "Creating example site object"
|
|
||||||
ex = Site(domain="example.com", name="example.com")
|
|
||||||
ex.save()
|
|
||||||
|
|
||||||
# If we just installed the User model, ask about creating a superuser
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
if User in created_models:
|
|
||||||
msg = "\nYou just installed Django's auth system, which means you don't have " \
|
|
||||||
"any superusers defined.\nWould you like to create one now? (yes/no): "
|
|
||||||
confirm = raw_input(msg)
|
|
||||||
while 1:
|
|
||||||
if confirm not in ('yes', 'no'):
|
|
||||||
confirm = raw_input('Please enter either "yes" or "no": ')
|
|
||||||
continue
|
|
||||||
if confirm == 'yes':
|
|
||||||
createsuperuser()
|
|
||||||
break
|
|
||||||
|
|
||||||
syncdb.args = ''
|
syncdb.args = ''
|
||||||
|
|
||||||
def get_admin_index(app):
|
def get_admin_index(app):
|
||||||
@ -585,30 +547,6 @@ The full error: %s\n""" % (app_name, app_name, e))
|
|||||||
reset.help_doc = "Executes ``sqlreset`` for the given app(s) in the current database."
|
reset.help_doc = "Executes ``sqlreset`` for the given app(s) in the current database."
|
||||||
reset.args = APP_ARGS
|
reset.args = APP_ARGS
|
||||||
|
|
||||||
def installperms(app):
|
|
||||||
"Installs any permissions for the given app, if needed."
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
|
||||||
from django.contrib.auth.models import Permission
|
|
||||||
from django.db.models import get_models
|
|
||||||
app_models = get_models(app)
|
|
||||||
if not app_models:
|
|
||||||
return
|
|
||||||
app_label = app_models[0]._meta.app_label
|
|
||||||
num_added = 0
|
|
||||||
for klass in app_models:
|
|
||||||
opts = klass._meta
|
|
||||||
ctype = ContentType.objects.get_for_model(klass)
|
|
||||||
for codename, name in _get_all_permissions(opts):
|
|
||||||
try:
|
|
||||||
Permission.objects.get(name=name, codename=codename, content_type__pk=ctype.id)
|
|
||||||
except Permission.DoesNotExist:
|
|
||||||
p = Permission(name=name, codename=codename, content_type=ctype)
|
|
||||||
p.save()
|
|
||||||
print "Adding permission '%r'." % p
|
|
||||||
num_added += 1
|
|
||||||
installperms.help_doc = "Installs any permissions for the given model module name(s), if needed."
|
|
||||||
installperms.args = APP_ARGS
|
|
||||||
|
|
||||||
def _start_helper(app_or_project, name, directory, other_name=''):
|
def _start_helper(app_or_project, name, directory, other_name=''):
|
||||||
other = {'project': 'app', 'app': 'project'}[app_or_project]
|
other = {'project': 'app', 'app': 'project'}[app_or_project]
|
||||||
if not _is_valid_dir_name(name):
|
if not _is_valid_dir_name(name):
|
||||||
@ -665,83 +603,6 @@ def startapp(app_name, directory):
|
|||||||
startapp.help_doc = "Creates a Django app directory structure for the given app name in the current directory."
|
startapp.help_doc = "Creates a Django app directory structure for the given app name in the current directory."
|
||||||
startapp.args = "[appname]"
|
startapp.args = "[appname]"
|
||||||
|
|
||||||
def createsuperuser(username=None, email=None, password=None):
|
|
||||||
"Creates a superuser account."
|
|
||||||
from django.core import validators
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
import getpass
|
|
||||||
|
|
||||||
try:
|
|
||||||
import pwd
|
|
||||||
except ImportError:
|
|
||||||
default_username = ''
|
|
||||||
else:
|
|
||||||
# Determine the current system user's username, to use as a default.
|
|
||||||
default_username = pwd.getpwuid(os.getuid())[0].replace(' ', '').lower()
|
|
||||||
|
|
||||||
# Determine whether the default username is taken, so we don't display
|
|
||||||
# it as an option.
|
|
||||||
if default_username:
|
|
||||||
try:
|
|
||||||
User.objects.get(username=default_username)
|
|
||||||
except User.DoesNotExist:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
default_username = ''
|
|
||||||
|
|
||||||
try:
|
|
||||||
while 1:
|
|
||||||
if not username:
|
|
||||||
input_msg = 'Username'
|
|
||||||
if default_username:
|
|
||||||
input_msg += ' (Leave blank to use %r)' % default_username
|
|
||||||
username = raw_input(input_msg + ': ')
|
|
||||||
if default_username and username == '':
|
|
||||||
username = default_username
|
|
||||||
if not username.isalnum():
|
|
||||||
sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
|
|
||||||
username = None
|
|
||||||
try:
|
|
||||||
User.objects.get(username=username)
|
|
||||||
except User.DoesNotExist:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
sys.stderr.write("Error: That username is already taken.\n")
|
|
||||||
username = None
|
|
||||||
while 1:
|
|
||||||
if not email:
|
|
||||||
email = raw_input('E-mail address: ')
|
|
||||||
try:
|
|
||||||
validators.isValidEmail(email, None)
|
|
||||||
except validators.ValidationError:
|
|
||||||
sys.stderr.write("Error: That e-mail address is invalid.\n")
|
|
||||||
email = None
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
while 1:
|
|
||||||
if not password:
|
|
||||||
password = getpass.getpass()
|
|
||||||
password2 = getpass.getpass('Password (again): ')
|
|
||||||
if password != password2:
|
|
||||||
sys.stderr.write("Error: Your passwords didn't match.\n")
|
|
||||||
password = None
|
|
||||||
continue
|
|
||||||
if password.strip() == '':
|
|
||||||
sys.stderr.write("Error: Blank passwords aren't allowed.\n")
|
|
||||||
password = None
|
|
||||||
continue
|
|
||||||
break
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
sys.stderr.write("\nOperation cancelled.\n")
|
|
||||||
sys.exit(1)
|
|
||||||
u = User.objects.create_user(username, email, password)
|
|
||||||
u.is_staff = True
|
|
||||||
u.is_active = True
|
|
||||||
u.is_superuser = True
|
|
||||||
u.save()
|
|
||||||
print "User created successfully."
|
|
||||||
createsuperuser.args = '[username] [email] [password] (Either all or none)'
|
|
||||||
|
|
||||||
def inspectdb(db_name):
|
def inspectdb(db_name):
|
||||||
"Generator that introspects the tables in the given database name and returns a Django model, one line at a time."
|
"Generator that introspects the tables in the given database name and returns a Django model, one line at a time."
|
||||||
from django.db import connection, get_introspection_module
|
from django.db import connection, get_introspection_module
|
||||||
@ -1120,11 +981,9 @@ run_shell.args = '[--plain]'
|
|||||||
|
|
||||||
DEFAULT_ACTION_MAPPING = {
|
DEFAULT_ACTION_MAPPING = {
|
||||||
'adminindex': get_admin_index,
|
'adminindex': get_admin_index,
|
||||||
'createsuperuser': createsuperuser,
|
|
||||||
'createcachetable' : createcachetable,
|
'createcachetable' : createcachetable,
|
||||||
'inspectdb': inspectdb,
|
'inspectdb': inspectdb,
|
||||||
'install': install,
|
'install': install,
|
||||||
'installperms': installperms,
|
|
||||||
'reset': reset,
|
'reset': reset,
|
||||||
'runserver': runserver,
|
'runserver': runserver,
|
||||||
'shell': run_shell,
|
'shell': run_shell,
|
||||||
@ -1145,7 +1004,6 @@ NO_SQL_TRANSACTION = (
|
|||||||
'adminindex',
|
'adminindex',
|
||||||
'createcachetable',
|
'createcachetable',
|
||||||
'install',
|
'install',
|
||||||
'installperms',
|
|
||||||
'reset',
|
'reset',
|
||||||
'sqlindexes'
|
'sqlindexes'
|
||||||
)
|
)
|
||||||
@ -1207,18 +1065,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING):
|
|||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
translation.activate('en-us')
|
translation.activate('en-us')
|
||||||
|
|
||||||
if action == 'createsuperuser':
|
if action == 'shell':
|
||||||
try:
|
|
||||||
username, email, password = args[1], args[2], args[3]
|
|
||||||
except IndexError:
|
|
||||||
if len(args) == 1: # We got no arguments, just the action.
|
|
||||||
action_mapping[action]()
|
|
||||||
else:
|
|
||||||
sys.stderr.write("Error: %r requires arguments of 'username email password' or no argument at all.\n")
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
action_mapping[action](username, email, password)
|
|
||||||
elif action == 'shell':
|
|
||||||
action_mapping[action](options.plain is True)
|
action_mapping[action](options.plain is True)
|
||||||
elif action in ('syncdb', 'validate'):
|
elif action in ('syncdb', 'validate'):
|
||||||
action_mapping[action]()
|
action_mapping[action]()
|
||||||
|
@ -8,3 +8,5 @@ post_save = object()
|
|||||||
|
|
||||||
pre_delete = object()
|
pre_delete = object()
|
||||||
post_delete = object()
|
post_delete = object()
|
||||||
|
|
||||||
|
post_syncdb = object()
|
||||||
|
@ -64,24 +64,6 @@ backend. See the `cache documentation`_ for more information.
|
|||||||
|
|
||||||
.. _cache documentation: http://www.djangoproject.com/documentation/cache/
|
.. _cache documentation: http://www.djangoproject.com/documentation/cache/
|
||||||
|
|
||||||
createsuperuser
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Creates a superuser account interactively. It asks you for a username, e-mail
|
|
||||||
address and password.
|
|
||||||
|
|
||||||
You can specify ``username email password`` on the command line, for convenient
|
|
||||||
use in shell scripts. Example::
|
|
||||||
|
|
||||||
django-admin.py createsuperuser john john@example.com mypassword
|
|
||||||
|
|
||||||
init
|
|
||||||
----
|
|
||||||
|
|
||||||
Initializes the database with the tables and data Django needs by default.
|
|
||||||
Specifically, these are the database tables from the ``auth`` and ``core``
|
|
||||||
models.
|
|
||||||
|
|
||||||
inspectdb [dbname]
|
inspectdb [dbname]
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
@ -128,13 +110,6 @@ install [modelmodule modelmodule ...]
|
|||||||
|
|
||||||
Executes the equivalent of ``sqlall`` for the given model module(s).
|
Executes the equivalent of ``sqlall`` for the given model module(s).
|
||||||
|
|
||||||
installperms [modelmodule modelmodule ...]
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
Installs any admin permissions for the given model module(s) that aren't
|
|
||||||
already installed in the database. Outputs a message telling how many
|
|
||||||
permissions were added, if any.
|
|
||||||
|
|
||||||
runserver [optional port number, or ipaddr:port]
|
runserver [optional port number, or ipaddr:port]
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user