Почему Django поднял IntegrityError: нулевое значение в столбце "user_id" нарушает ограничение not-null при фиксации формы?

У меня есть модель UserSession, которая создает сеанс, который использует IP-адрес и городские данные для заполнения модели с использованием Geip2. Я настроил форму, которая берет информацию, которую я хочу, чтобы пользователь ввел, но получаю:

**django.db.utils.IntegrityError: null value in column "user_id" violates not-null constraint**

когда я отправляю форму. Объект создается, но информация, которую получает форма, не сохраняется в объекте.

Просмотры:

class NewLocationCreateForm(CreateView):
        model = UserSession
        success_url = reverse_lazy('post:index')
        form_class = NewLocationCreateForm



 def form_valid(self, form):
        if form.is_valid():
            roote = Post.objects.filter(owner =self.request.user)
            instance = form.save(commit=False)
            instance.owner = self.request.user
            user_logged_in.send(self.request.user, request=self.request)
        return super(NewLocationCreateForm, self).form_valid(form)


    def get_form_kwargs(self):
        kwargs = super(NewLocationCreateForm, self).get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs

Кажется, проблема заключается в следующем:

if form.is_valid():
 return super(NewLocationCreateForm, self).form_valid(form) 

Вызов сеанса пользователя Geoip2, кажется, работает, но не сохраняет форму

forms.py

from .models import  UserSession
from post.models import  Post
from django import forms


class NewLocationCreateForm(forms.ModelForm):

    class Meta:
        model = UserSession
        fields = [
            'g_post',
            'coordinate',
            'place_name'
        ]
    def __init__(self,user=None, *args, **kwargs):
        super(NewLocationCreateForm, self).__init__(*args, **kwargs)
        self.fields['g_post'].queryset = Post.objects.filter(owner=user)

models.py:

from django.conf import settings
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
from django.db.models.signals import pre_save
from analytics.signals import user_logged_in
from analytics.utils import get_client_city_data, get_client_ip
from post.models import Post
User = settings.AUTH_USER_MODEL


class UserSessionManager(models.Manager):
    def create_new(self, user, session_key=None, ip_address=None, city_data=None):
        session_new = self.model()
        session_new.user = user
        session_new.session_key = session_key
        if ip_address is not None:
            session_new.ip_address = ip_address
            if city_data:
                session_new.city_data = city_data
                try:
                    city = city_data['city']
                except:
                    city = None
                session_new.city = city
                try:
                    country = city_data['country_name']
                except:
                    country = None
            session_new.country = country
            session_new.save()
            return session_new
        return None

class UserSession(models.Model):
    g_post            = models.ForeignKey(Post, on_delete=models.CASCADE, null=True)
    user            = models.ForeignKey(User)
    coordinate      = models.CharField(max_length=1000, blank=True)
    place_name      = models.CharField(max_length=250, blank=True)
    location_photo  = models.ImageField(upload_to='location_image', blank=True)
    updated         = models.DateTimeField(auto_now=True, null=True)
    session_key     = models.CharField(max_length=60, null=True, blank=True)
    ip_address      = models.GenericIPAddressField(null=True, blank=True)
    city_data       = models.TextField(null=True, blank=True)
    city            = models.CharField(max_length=120, null=True, blank=True)
    country         = models.CharField(max_length=120, null=True, blank=True)
    active          = models.BooleanField(default=True)
    timestamp       = models.DateTimeField(auto_now_add=True)

    objects = UserSessionManager()

    def __str__(self):
        city = self.city
        country = self.country
        place_name = self.place_name
        if city and country:
            return f"{city}, {country}"
        elif city and not country:
            return f"{city}"
        elif country and not city:
            return f"{country}"
        return self.place_name    

def user_logged_in_receiver(sender, request, *args, **kwargs):
    user = sender
    ip_address = get_client_ip(request)
    city_data = get_client_city_data(ip_address)
    request.session['CITY'] = str(city_data.get('city', 'New York'))
    session_key = request.session.session_key
    UserSession.objects.create_new(
                user=user,
                session_key=session_key,
                ip_address=ip_address,
                city_data=city_data
                )



user_logged_in.connect(user_logged_in_receiver)

2 ответа

Решение

Рядом с исправлением @solarissmoke (изменение instance.owner в instance.user), который исправляет IntegrityError, вы запускаете user_logged_in() сигнал в is_valid() метод здесь:

def form_valid(self, form):
    if form.is_valid():
        roote = Post.objects.filter(owner =self.request.user)
        instance = form.save(commit=False)
        instance.user = self.request.user
        # Here you trigger signal that creates UserSession!
        user_logged_in.send(self.request.user, request=self.request)
    return super(NewLocationCreateForm, self).form_valid(form)

Поэтому один объект создается с помощью CreateView, а другой - с этим сигналом. Удалить эту строку в form_valid(),

РЕДАКТИРОВАТЬ: Чтобы включить данные из сигнала, просто добавьте это к form_valid() как это:

def form_valid(self, form):
    if form.is_valid():
        roote = Post.objects.filter(owner =self.request.user)
        instance = form.save(commit=False)
        instance.user = self.request.user
        instance.ip_address = get_client_ip(self.request)
        instance.city_data = get_client_city_data(instance.ip_address)
        instance.session_key = self.request.session.session_key
    return super(NewLocationCreateForm, self).form_valid(form)

Ваш UserSession модель не имеет owner поле определено, поэтому установка этого экземпляра вам не поможет. Вы, вероятно, хотите сделать это вместо этого:

if form.is_valid():
    roote = Post.objects.filter(owner =self.request.user)
    instance = form.save(commit=False)
    instance.user = self.request.user   # You need to set instance.user, not instance.owner
    user_logged_in.send(self.request.user, request=self.request)
    return super(NewLocationCreateForm, self).form_valid(form)
Другие вопросы по тегам