具有多个数据库和应用程序特定路由器的 Django,无法在 MSSQL 中添加用户
Django with multiple databases and app specific routers, cannot add users in MSSQL
我们有一个连接到多个 MS SQL 数据库实例的 Django 应用程序。每个应用程序都有一个 router.py 处理将进程路由到每个数据库。
这是我第一次设置多数据库访问。
Django 内置应用程序通过此 router.py:
路由到默认数据库
class DjangoRouter(object):
"""
A router to control all database operations on models in the
auth application.
"""
def db_for_read(self, model, **hints):
"""
Attempts to read auth models go to auth.
"""
app_list = ('auth', 'admin', 'contenttypes', 'sessions',)
if model._meta.app_label in app_list:
return 'default'
return None
def db_for_write(self, model, **hints):
"""
Attempts to write auth models go to auth.
"""
app_list = ('auth', 'admin', 'contenttypes', 'sessions',)
if model._meta.app_label in app_list:
return 'default'
return None
def allow_relation(self, obj1, obj2, **hints):
"""
Allow relations if a model in the auth app is involved.
"""
app_list = ('auth', 'admin', 'contenttypes', 'sessions',)
if obj1._meta.app_label in app_list and obj2._meta.app_label in app_list:
return True
return None
def allow_migrate(self, db, app_label, model=None, **hints):
"""
Make sure the auth app only appears in the 'auth'
database.
"""
app_list = ('auth', 'admin', 'contenttypes', 'sessions',)
if app_label in app_list:
return db == 'default'
return None
我们正在使用 LDAP 身份验证和 Django 的内置身份验证。这个想法是 Intranet 用户可以对我们的 AD 服务器进行身份验证。外部用户可以注册,并且会通过Django的认证进行认证。
当我将默认数据库设置为:
'default': {
'ENGINE': 'sql_server.pyodbc',
'NAME': 'Django',
'USER': '',
'PASSWORD': '',
'HOST': 'sqlbeta',
'PORT': '',
},
LDAP 有效,但我无法将用户添加到 Django 的身份验证中。管理员显示 "success" 消息,但用户未添加到数据库。
如果我将默认数据库切换回 SQLLite,我可以针对 AD 进行身份验证并添加 Django 用户。
所以,我不认为这是 routers.py 文件的问题。我担心这可能是 'sql_server.pyodbc' 引擎的问题。
编辑:
根据请求,这里是数据库设置:
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# },
'default': {
'ENGINE': 'sql_server.pyodbc',
'NAME': 'Django',
'USER': '',
'PASSWORD': '',
'HOST': 'sqlbeta',
'PORT': '',
},
'master': {
'ENGINE': 'sql_server.pyodbc',
'NAME': 'master',
'USER': '',
'PASSWORD': '',
'HOST': 'sqlbeta',
'PORT': '',
},
'databaseone': {
'ENGINE': 'sql_server.pyodbc',
'NAME': 'databaseone',
'USER': '',
'PASSWORD': '',
'HOST': 'sqlbeta',
'PORT': '',
},
'databasetwo': {
'ENGINE': 'sql_server.pyodbc',
'NAME': 'databasetwo',
'USER': '',
'PASSWORD': '',
'HOST': 'sqlbeta',
'PORT': '',
},
}
注意:
我认为这可能与 Django 保存新用户的方式有关。要去那里看看。我可以使用 createsuperuser 命令添加更多超级用户,同时两个身份验证后端都已到位。确认,我可以通过 shell 创建普通用户,但不能通过管理员。
跟进说明:
仍然没有找到管理员的问题,但我发现我可以通过表单添加用户。我认为问题一定是管理员中的错误。
编辑:
根据@AndrewSmiley 的请求:
class UserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'password_mismatch': _("The two password fields didn't match."),
}
password1 = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
class Meta:
model = User
fields = ("username",)
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
更新:
根据@user1797792 的建议,我创建了一个自定义 UserCreationForm 来设置 date_joined
值,但我们仍然无法通过 Django 管理添加用户。
相关 forms.py 和 admin.py 条目如下:
class CustomUserCreationForm(UserCreationForm):
now = timezone.now()
class Meta:
model = User
fields = ('username',)
def save(self, commit=True):
user = super(CustomUserCreationForm, self).save(commit=False)
user.date_joined = self.now
if commit:
user.save()
return user
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
我认为可空字段存在问题,并且 UserCreationForm 中存在错误。我无法重现这个问题,因为我没有 MSSQL 服务器。
https://github.com/django/django/blob/1.8.6/django/contrib/auth/models.py#L185
该函数由管理命令使用。它为 date_joined
属性 生成一个 timezone.now(),而管理面板中的表单只是在对象本身上使用 save() 函数,它不会执行此操作。
如果您在管理面板中创建用户,date_joined
似乎保留为 NULL。你能检查这个列在 MSSQL 数据库中是否有默认值吗?并且是可空的。
如果没有,则它不可为空。那么他们就是你的问题。
然后您应该编辑 UserCreationForm。 Here is a Whosebug entry 向您展示如何执行此操作。
在遵循了通过评论和答案提交的所有建议之后。我们意识到问题是 django-pyodbc-azure
库中一个未记录的错误。
启动 PostgreSQL 数据库并连接我们的 Django 应用程序后,我们无法重现此错误。我们还使用 FreeTDS/ODBC 驱动程序与 MSSQL 数据库进行通信,但无法重新创建它。
我们有一个连接到多个 MS SQL 数据库实例的 Django 应用程序。每个应用程序都有一个 router.py 处理将进程路由到每个数据库。
这是我第一次设置多数据库访问。
Django 内置应用程序通过此 router.py:
路由到默认数据库class DjangoRouter(object):
"""
A router to control all database operations on models in the
auth application.
"""
def db_for_read(self, model, **hints):
"""
Attempts to read auth models go to auth.
"""
app_list = ('auth', 'admin', 'contenttypes', 'sessions',)
if model._meta.app_label in app_list:
return 'default'
return None
def db_for_write(self, model, **hints):
"""
Attempts to write auth models go to auth.
"""
app_list = ('auth', 'admin', 'contenttypes', 'sessions',)
if model._meta.app_label in app_list:
return 'default'
return None
def allow_relation(self, obj1, obj2, **hints):
"""
Allow relations if a model in the auth app is involved.
"""
app_list = ('auth', 'admin', 'contenttypes', 'sessions',)
if obj1._meta.app_label in app_list and obj2._meta.app_label in app_list:
return True
return None
def allow_migrate(self, db, app_label, model=None, **hints):
"""
Make sure the auth app only appears in the 'auth'
database.
"""
app_list = ('auth', 'admin', 'contenttypes', 'sessions',)
if app_label in app_list:
return db == 'default'
return None
我们正在使用 LDAP 身份验证和 Django 的内置身份验证。这个想法是 Intranet 用户可以对我们的 AD 服务器进行身份验证。外部用户可以注册,并且会通过Django的认证进行认证。
当我将默认数据库设置为:
'default': {
'ENGINE': 'sql_server.pyodbc',
'NAME': 'Django',
'USER': '',
'PASSWORD': '',
'HOST': 'sqlbeta',
'PORT': '',
},
LDAP 有效,但我无法将用户添加到 Django 的身份验证中。管理员显示 "success" 消息,但用户未添加到数据库。
如果我将默认数据库切换回 SQLLite,我可以针对 AD 进行身份验证并添加 Django 用户。
所以,我不认为这是 routers.py 文件的问题。我担心这可能是 'sql_server.pyodbc' 引擎的问题。
编辑: 根据请求,这里是数据库设置:
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# },
'default': {
'ENGINE': 'sql_server.pyodbc',
'NAME': 'Django',
'USER': '',
'PASSWORD': '',
'HOST': 'sqlbeta',
'PORT': '',
},
'master': {
'ENGINE': 'sql_server.pyodbc',
'NAME': 'master',
'USER': '',
'PASSWORD': '',
'HOST': 'sqlbeta',
'PORT': '',
},
'databaseone': {
'ENGINE': 'sql_server.pyodbc',
'NAME': 'databaseone',
'USER': '',
'PASSWORD': '',
'HOST': 'sqlbeta',
'PORT': '',
},
'databasetwo': {
'ENGINE': 'sql_server.pyodbc',
'NAME': 'databasetwo',
'USER': '',
'PASSWORD': '',
'HOST': 'sqlbeta',
'PORT': '',
},
}
注意: 我认为这可能与 Django 保存新用户的方式有关。要去那里看看。我可以使用 createsuperuser 命令添加更多超级用户,同时两个身份验证后端都已到位。确认,我可以通过 shell 创建普通用户,但不能通过管理员。
跟进说明: 仍然没有找到管理员的问题,但我发现我可以通过表单添加用户。我认为问题一定是管理员中的错误。
编辑:
根据@AndrewSmiley 的请求:
class UserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'password_mismatch': _("The two password fields didn't match."),
}
password1 = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
class Meta:
model = User
fields = ("username",)
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
更新:
根据@user1797792 的建议,我创建了一个自定义 UserCreationForm 来设置 date_joined
值,但我们仍然无法通过 Django 管理添加用户。
相关 forms.py 和 admin.py 条目如下:
class CustomUserCreationForm(UserCreationForm):
now = timezone.now()
class Meta:
model = User
fields = ('username',)
def save(self, commit=True):
user = super(CustomUserCreationForm, self).save(commit=False)
user.date_joined = self.now
if commit:
user.save()
return user
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
我认为可空字段存在问题,并且 UserCreationForm 中存在错误。我无法重现这个问题,因为我没有 MSSQL 服务器。
https://github.com/django/django/blob/1.8.6/django/contrib/auth/models.py#L185
该函数由管理命令使用。它为 date_joined
属性 生成一个 timezone.now(),而管理面板中的表单只是在对象本身上使用 save() 函数,它不会执行此操作。
date_joined
似乎保留为 NULL。你能检查这个列在 MSSQL 数据库中是否有默认值吗?并且是可空的。
如果没有,则它不可为空。那么他们就是你的问题。
然后您应该编辑 UserCreationForm。 Here is a Whosebug entry 向您展示如何执行此操作。
在遵循了通过评论和答案提交的所有建议之后。我们意识到问题是 django-pyodbc-azure
库中一个未记录的错误。
启动 PostgreSQL 数据库并连接我们的 Django 应用程序后,我们无法重现此错误。我们还使用 FreeTDS/ODBC 驱动程序与 MSSQL 数据库进行通信,但无法重新创建它。