为什么Django引发IntegrityError:列“user_id”中的null值在提交表单时违反了非空约束?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么Django引发IntegrityError:列“user_id”中的null值在提交表单时违反了非空约束?相关的知识,希望对你有一定的参考价值。

我有一个UserSession模型,它创建一个使用IPaddress的会话,以及使用Geip2填充模型的城市数据。我设置了一个表单,其中包含我希望用户输入的信息,但获取:

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

当我提交表格时。创建对象但表单所采用的信息不会保存到对象。

views:

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)
答案

在修复IntegrityError的@solarissmoke修改(更改instance.ownerinstance.user)旁边,你在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)

以上是关于为什么Django引发IntegrityError:列“user_id”中的null值在提交表单时违反了非空约束?的主要内容,如果未能解决你的问题,请参考以下文章

ActiveStorage::IntegrityError 何时引发?

IntegrityError:重复键值违反唯一约束

SQLAlchemy 关联表(关联对象模式)引发 IntegrityError

IntegrityError 中缺少表名(Django ORM)

Django写入数据库,IntegrityError

django:IntegrityError:重复键值违反唯一约束