我想捕获当前登录用户的用户名,而不是pk。
incident.username = request.user
不起作用
incident.username = request.user.username
不起作用
incident.username = request.username
不起作用
Uggg。这不可能是这么难。
models.py
class Incident(models.Model):
username = models.ForeignKey(User) ## field in db will be auto-populated by view.py
date_reported = models.DateField() ## field in db will be auto-populated by view.py
date_occurred = models.DateField()
number_of_samples_affected = models.IntegerField()
capa = models.CharField(max_length=9)
title = models.CharField(max_length=100)
description = models.TextField()
status = models.ForeignKey(Status) ## field in db will be auto-populated by view.py to "Open" at form submission
category = models.ForeignKey(Category)
lab = models.TextField(Lab)
views.py
from submit_app.forms import IncidentForm
from submit_app.models import Incident, Status
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
import datetime
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
@login_required(login_url='/login/')
def submit(request):
if request.GET:
form = IncidentForm()
template = 'submit.html'
context = {'form': form}
return render(request, template, context)
# if this is a POST request we need to process the form data
if request.POST:
# create a form instance and populate it with the data from the request:
form = IncidentForm(request.POST)
# check whether it's valid:
if form.is_valid():
incident = form.save(False) # creating an incident object, but not saving it to the db just yet
incident.username = request.user # auto capture logged in user
incident.date_reported = datetime.date.today() # auto capture the incident submission date
incident.status = Status.objects.get(status="open") # trying to auto populate status with 'Open' upon submission (foreign key)
incident.save()
return HttpResponseRedirect(reverse('dashboard_app:dashboard'))
form = IncidentForm()
template = 'submit.html'
context = {'form': form}
return render(request, template, context)
答案 0 :(得分:2)
目前,您的模型与User
模型具有外键关系,默认情况下与主键字段相关。要更改该内容并与username
字段本身相关联,请在模型to_field
和makemigrations
中添加migrate
关键字参数。
username = models.ForeignKey(User,to_field='username')
之后,您可以通过request.user.username
访问当前请求的用户,假设username
是User
的字段/属性(而不是相关的)模型)。
...
但是,通常不需要这样做。您仍然可以与User
模型(通过PK构建的关系)相关联,并从那里访问用户名。最简单的方法是创建一个读取用户名的方法。
class Incident(models.Model):
user = models.ForeignKey(User, related_name='incidents')
def username(self):
if self.user:
return getattr(self.user,'username',None) # attempt to access username
...
>>> first_incident = Incident.objects.create(user=User.objects.get(username='a'))
>>> print(first_incident.username())
a
答案 1 :(得分:1)
有一些明显的混乱。 Incident.username是User模型的外键,因此需要为其分配User对象,而不仅仅是用户名。因为force_reapprove
应该有效。您可以稍后通过访问incident.username = request.user
来访问用户名,但我会将该字段重命名为user以避免混淆。如果这不起作用,某些东西不能正常工作。如果您发布了错误,这将有所帮助。
答案 2 :(得分:0)
您应该使用自定义用户模型并将usename字段指定为主键。但是在django中,模型的抽象基类不能具有“覆盖字段”,因此您需要升级AbstractBaseUser
而不是AbstractUser
。您最终可能会得到AbstractUser
代码(https://github.com/django/django/blob/1.8.9/django/contrib/auth/models.py#L378)的副本
只更改了一行:
来自django.contrib.auth.models导入AbstractBaseUser,PermissionsMixin,验证器,UserManager
class MyUser(AbstractBaseUser, PermissionsMixin):
username = models.CharField(_('username'), max_length=30, unique=True,
primary_key=True, ## the only difference from AbstractUser help_text=_('Required. 30 characters or fewer. Letters, digits and '
'@/./+/-/_ only.'),
validators=[
validators.RegexValidator(r'^[\w.@+-]+$',
_('Enter a valid username. '
'This value may contain only letters, numbers '
'and @/./+/-/_ characters.'), 'invalid'),
],
error_messages={
'unique': _("A user with that username already exists."),
})
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(_('email address'), blank=True)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user can log into this admin '
'site.'))
is_active = models.BooleanField(_('active'), default=True,
help_text=_('Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
abstract = True
def get_full_name(self):
"""
Returns the first_name plus the last_name, with a space in between.
"""
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
"Returns the short name for the user."
return self.first_name
def email_user(self, subject, message, from_email=None, **kwargs):
"""
Sends an email to this User.
"""
send_mail(subject, message, from_email, [self.email], **kwargs)
在此之后,您将能够将FK字段指向用户名字段。但你真的需要这个吗?为什么你需要这样的FK?主键最好是“静态”。通过使用用户名作为主键,您将无法更改用户名。
我可以想象出这样一个要求的几个原因:
您希望您的事件指向特定用户名而不是实际用户(可能您的用户实例可能会被删除,之后会使用相同的用户名重新创建?)。这很奇怪但可以完成:使用username = CharField(...)
并使用getter和setter为user指定属性。
class Incident(models.Model):
username = models.CharField(max_length=30)
@property
def user(self):
return User.objects.get(username=self.username)
@user.setter
def user(self, user):
if user.is_authenticated():
self.username = user.username
else:
self.username = '#anonymous' # by default '#' is disallowed in username. You can also make your username nullable
您想“优化”数据库调用(不查询用户表)。在这种情况下,您最好使用预取或非规范化:
from django.db import models
# prefetch user with only "username" field. Assuming that you have `Incident.user = models.ForeignKey(...)`. Read https://docs.djangoproject.com/en/1.9/topics/db/managers/ and https://docs.djangoproject.com/en/1.9/ref/models/querysets/#prefetch-related
class IncidentManager(models.Manager):
def get_queryset(self):
return super(IncidentManager, self).get_queryset().prefetch_related(models.Prefetch('user', queryset=User.objects.all().only('username'))
class Incident(models.Model):
user = models.ForeignKey(User)
# ...
objects = IncidentManager()
如果是非规范化,你应该为User
模型的post_save和post_delete信号创建接收器,该信号应该用实际用户名更新Incident.username
字段。您还必须为Incident的post_save / post_delete创建类似的信号接收器(或者您可以修改Incident.save
和Incident.delete
方法)。您还可以为admin.models.LogAction
post_save信号(from django.contrib.admin.models import DELETEION; if instance.action_flag == DELETEION and instance.content_type_id=get_content_type_for_model(Incident).pk:
)创建信号接收器,因为django-admin的大量删除不会调用Incident.delete
,也不会针对已删除的incidnets触发post_delete
。如果您在项目中的任何位置使用User.object.update(username=something)
或者数据直接在数据库中更改,那么即使此非规范化数据可能无效。