I have a UserSession model that creates a session that uses the IPaddress, and city data to populate the model using Geip2. I set up a form that takes the info that I want the user to enter but get:
**django.db.utils.IntegrityError: null value in column "user_id" violates not-null constraint**
when I submit the form. The object gets created but the information that the form takes doesn't save to the object.
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
The problem seems to arrive at at is:
if form.is_valid():
return super(NewLocationCreateForm, self).form_valid(form)
The user session call of the Geoip2 seems to work but it doesn't save the form
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)
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)
Next to the fix by @solarissmoke (changing instance.owner
to instance.user
) which fixes IntegrityError, you are triggering user_logged_in()
signal in the is_valid()
method here:
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)
One object is therefore created with the CreateView and another one with this signal. Remove this line in form_valid()
.
EDIT: To include data from signal, simply add this to form_valid()
like this:
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)