2016-02-25 6 views
0

Я хочу захватить имя пользователя, который в настоящее время вошел в систему, а не pk.Django: автоматический выбор имени пользователя из модели пользователя. not 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

Каковы симптомы? Есть ли сообщение об ошибке? – jcfollower

ответ

1

Существует некоторая путаница очевидна. Incident.username - это внешний ключ модели пользователя, поэтому ему должен быть назначен объект User, а не только имя пользователя. Для этого incident.username = request.user должен работать. Вы можете позже получить доступ к имени пользователя, обратившись к incident.username.username, хотя я бы переименовал поле для пользователя, чтобы избежать путаницы. Если это не работает, что-то не работает должным образом. Это поможет, если вы разместите ошибку, которую вы получаете.

+0

Я хочу сохранить имя пользователя в имени пользователя Incident Model, а не pk. Итак, я объединил ваш ответ с приведенным выше. Я попробовал 'username = models.ForeignKey (User, to_field = 'username')' и 'case.username = request.user.username', но я все еще получил' Can not assign '' msmith ': «Incident.username» должен быть экземпляром «Пользователь». – user1807271

+0

Я думаю, что я концептуально отсутствует ссылка – user1807271

+0

Если вы хотите сохранить имя пользователя, просто введите имя пользователя CharField и сохраните имя пользователя в виде строки. Независимо от того, какое поле вы используете в to_field, Django по-прежнему будет обрабатывать внешний ключ как полный объект, а не одно поле. Тем не менее, при создании внешних ключей Django создает связанный с ним поле для хранения идентификатора внешнего ключа, поэтому с вашим 'username = models.ForeignKey (User, to_field = 'username')' вы должны иметь возможность назначить 'инцидент. username_username' или что-то еще и по-прежнему поддерживать какую-то целостность базы данных –

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 
+0

, когда я делаю первую поправку, которую вы даете. Я получаю сообщение об ошибке «Не могу назначить» «msmith»: «Incident.username» должен быть экземпляром «Пользователь». Если по какой-то причине он не сохранит имя пользователя. Честно говоря, я просто не знаю, как интерпретировать ошибку. – user1807271

0

Вы должны использовать пользовательскую модель пользователя и указать поле имени пользователя как первичный ключ. Но в 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'^[\[email protected]+-]+$', 
             _('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? Первичные ключи должны быть более «статичными». Используя имя пользователя в качестве первичного ключа, у вас возникнут проблемы с изменением имен пользователей.

Я могу представить себе несколько причин для такого требования: (? Может быть, ваши экземпляры пользователя могут быть удалены, а затем воссозданы с тем же именем)

  1. Вы хотите, чтобы ваши случаи указать конкретное имя вместо фактического пользователя , Это странно, но можно сделать: используйте username = CharField(...), а также укажите свойство для пользователя с геттером и сеттером.

    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 
    
  2. вы хотите, чтобы «оптимизировать» вызовы базы данных (не запрашивать таблицу пользователей). В этом случае лучше использовать предзапросы или денормализацию:

    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() 
    

    В случае денормализации вы должны создать приемник для post_save и post_delete сигналов для User модели, которая должна обновить Incident.username поля с действительным именем пользователя. Вы также должны создавать аналогичные приемники сигналов для post_save/post_delete (или вы можете изменить методы Incident.save и Incident.delete). Вы также можете создать приемник сигнала для admin.models.LogAction post_save signal (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 и не вызывает post_delete для удаленных заносов. И даже после того, как эти денормализованные данные могут быть недействительными, если вы используете User.object.update(username=something) в любом месте вашего проекта или данные напрямую изменяются в базе данных.

Смежные вопросы