Django部署阿里云同步数据库报错及ForeignKey参数详解
本文记录在阿里云Ubuntu环境下部署Django博客时遇到的数据库同步报错及超级用户创建失败问题。通过修正STATIC_ROOT路径配置解决同步错误,并发现后台账号权限关闭导致无法登录。此外,详细解析Django 2.0+中ForeignKey的on_delete参数(CASCADE、PROTECT、SET_NULL等)及其在一对多、一对一和多对多关系中的具体应用与代码示例。
阿里云Django部署数据库同步报错排查
前言说明:
在阿里云服务器搭建博客系统,技术栈采用Ubuntu操作系统、Django框架、uWSGI应用服务器、Nginx反向代理以及MySQL数据库。
系统运行一段时间后,发现忘记了Django自带后台管理系统的登录密码。
尝试执行常规的密码修改操作,但始终无法成功登录后台。
随后尝试创建新的超级用户以排查情况,却遭遇创建报错。
本地开发环境运行正常,但生产环境同步数据库时出现错误,导致整体流程受阻。
同步数据库时的具体报错信息如下所示:

上述报错截图经查询分析,推测为settings.py配置文件存在问题,因此将生产环境的代码下载下来进行排查。
具体配置代码如下:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
#os.path.join(os.path.dirname(__file__), '../static/').replace('\\', '/'),
)
需要注意的是,STATIC_ROOT与STATICFILES_DIRS这两个配置项只需保留其中一个即可生效。
若必须同时配置两者,
请确保
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
修改为
STATIC_ROOT = os.path.join(BASE_DIR, '/static/')
完成上述修改后,再次执行数据库同步操作。
此时,创建超级用户的操作也已恢复正常。
登录Admin后台后发现,原账号的权限已被关闭,这解释了为何之前修改密码无效。
后续将详细整理在阿里云部署Django的完整过程。
Django ForeignKey on_delete参数详解
补充知识:Django 2.0中ForeignKey关于on_delete参数的提示。
在Django 2.0版本之前,创建外键(ForeignKey)时on_delete参数存在默认值,因此可以省略不写。但在2.0及之后的版本中,该参数不再提供默认值,必须显式传入,否则将触发以下错误:
TypeError: __init__() missing 1 required positional argument: on_delete
接下来详细说明on_delete参数各选项的具体含义。
on_delete=None, # 删除关联表中的数据时,当前表与其关联的field的行为(注:此选项通常不推荐,具体行为依赖数据库约束)
on_delete=models.CASCADE, # 删除关联数据时,当前表中与之关联的数据也会被级联删除
on_delete=models.DO_NOTHING, # 删除关联数据时,不做任何操作(需依赖数据库外键约束处理)
on_delete=models.PROTECT, # 删除关联数据时,若存在关联记录则引发ProtectedError错误
# models.ForeignKey('关联表', on_delete=models.SET_NULL, blank=True, null=True)
on_delete=models.SET_NULL, # 删除关联数据时,将当前表中关联字段的值设置为null(前提是该字段允许为NULL,一对一关系同理)
# models.ForeignKey('关联表', on_delete=models.SET_DEFAULT, default='默认值')
on_delete=models.SET_DEFAULT, # 删除关联数据时,将当前表中关联字段的值设置为默认值(前提是该字段设置了默认值,一对一关系同理)
on_delete=models.SET, # 删除关联数据时,
a. 将关联字段的值设置为指定值,设置方式:models.SET(值)
b. 将关联字段的值设置为可执行对象的返回值,设置方式:models.SET(可执行对象)
外键关系创建与代码示例
示例:创建一对多外键关系。
class UserType(models.Model):
caption = models.CharField(max_length=32)
class UserInfo(models.Model):
user = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey(to="UserType",to_field="id",on_delete=models.CASCADE)
定义外键后,使用models.xxxx.objects.create()创建数据时,外键字段的值需要传入关联表的对象实例,如下所示:
class UserType(models.Model):
caption = models.CharField(max_length=32)
class UserInfo(models.Model):
user = models.CharField(verbose_name='用户', max_length=32)
email = models.EmailField()
user_type = models.ForeignKey(to="UserType",to_field="id",on_delete=models.CASCADE)
-----------上面是的是在models.py,下面的是在views.py-------------
def test(requset):
ut = models.UserType.objects.filter(id=1).first()
#print(ut)
models.UserInfo.objects.create(user='小明',email='abc@163.com',user_type=ut)
return HttpResponse('ok')
一对多关系的继承代码示例:
class ForeignKey(ForeignObject):
def __init__(self, to, on_delete, related_name=None, related_query_name=None,
limit_choices_to=None, parent_link=False, to_field=None,
db_constraint=True, **kwargs):
super().__init__(to, on_delete, from_fields=['self'], to_fields=[to_field], **kwargs)
创建一对一关系。
OneToOneField(ForeignKey)
to, # 要进行关联的表名
to_field=None # 要关联的表中的字段名称
on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
###### 对于一对一 ######
# 1. 一对一其实就是 一对多 + 唯一索引
# 2.当两个类之间有继承关系时,默认会创建一个一对一字段
# 如下会在A表中额外增加一个c_ptr_id列且唯一:
class C(models.Model):
nid = models.AutoField(primary_key=True)
part = models.CharField(max_length=12)
class A(C):
id = models.AutoField(primary_key=True)
code = models.CharField(max_length=1)
一对一关系的继承代码示例:
class OneToOneField(ForeignKey):
def __init__(self, to, on_delete, to_field=None, **kwargs):
kwargs['unique'] = True
super().__init__(to, on_delete, to_field=to_field, **kwargs)
多对多关系处理与前端展示
创建多对多关系。
方式一:通过自定义中间表建立关系。
class Host(models.Model):
nid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
port = models.IntegerField()
b = models.ForeignKey(to="Business", to_field='id')
# 10
class Application(models.Model):
name = models.CharField(max_length=32)
# 2
class HostToApp(models.Model):
hobj = models.ForeignKey(to='Host',to_field='nid')
aobj = models.ForeignKey(to='Application',to_field='id')
# HostToApp.objects.create(hobj_id=1,aobj_id=2)这里可以直接对第三张表直接操
方式二:利用Django自动创建关系表。
class Host(models.Model):
nid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
port = models.IntegerField()
b = models.ForeignKey(to="Business", to_field='id')
# 10
class Application(models.Model):
name = models.CharField(max_length=32)
r = models.ManyToManyField("Host") --------------> appname_application_r 表名
无法直接对第三张关系表进行常规ORM操作。
只能通过关联对象间接操作————————————————————
obj = models.Application.objects.get(id=1)
obj.name
# 第三张表操作:HostToApp table 基于id=1的Application添加对应关系
obj.r.add(1)增
obj.r.add(2)
obj.r.add(2,3,4)
obj.r.add(*[1,2,3,4])
obj.r.remove(1) 删
obj.r.remove(2,4)
obj.r.remove(*[1,2,3])
obj.r.clear() 清除app_id =1 的列
obj.r.set([3,5,7]) 改set将原来数据库中的关系先全部删除,在添加1-3,1-5,1-7
——————————————————————————
# 所有相关的主机对象“列表” QuerySet
obj.r.all() obj.filter() obj.first()
前端模板获取数据。
{%for app in app_list%}
<tr>
<td>{{app.name}}</td>
<td>{{app.r.all}}</td>
</tr>
{%endfor%}
多对多关系的继承代码示例:
class ManyToManyField(RelatedField):
def __init__(self, to, related_name=None, related_query_name=None,
limit_choices_to=None, symmetrical=None, through=None,
through_fields=None, db_constraint=True, db_table=None,
swappable=True, **kwargs):
super().__init__(**kwargs)
以上关于Django解决阿里云部署同步数据库报错及ForeignKey参数用法的分享到此结束,希望能对读者有所帮助,欢迎支持。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













