Why does Django raised IntegrityError :null value in column "user_id" violates not-null constraint when a form is committed?

Why does Django raised IntegrityError :null value in column "user_id" violates not-null constraint when a form is committed?

我有一个 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)

您的 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)

在修复 IntegrityError 的@solarissmoke 修复(将 instance.owner 更改为 instance.user)之后,您在此处的 is_valid() 方法中触发了 user_logged_in() 信号:

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)