I use the basic user model, and i'd like to have a profile connected to it aswell. But when I submit my form i get this error: NOT NULL constraint failed: users_profile.user_id
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
# Create your models here.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, unique=True)
weight = models.FloatField(max_length=20, blank=True, null=True)
height = models.FloatField(max_length=20, blank=True, null=True)
goal = models.FloatField(max_length=20, blank=True, null=True)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_profile(sender,instance,created,**kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender,instance,**kwargs):
instance.profile.save()
Views:
from django.shortcuts import render
from django.contrib import messages
from users import models
from users.models import Profile
from .forms import WeightForm
# Create your views here.
def home(request):
form = WeightForm()
if request.method == 'POST':
form = WeightForm(request.POST)
if form.is_valid:
form.save()
return render(request, 'Landing/index.html', {'form': form})
The problem is that your "update" case is running before the create case. Instead of having two receivers, use one with a condition on created.
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
else:
instance.profile.save()
Related
please help me with one question, if possible.
I have a profile model that has a OneToOneField to User and there is a team field in the Profile model, there is also a Team model with a name, tag, etc. I would like to ask how to make the user who creates the team immediately be in it, so that the team field of the Profile model is assigned this team automatically, so that he is its creator and captain immediately. Maybe someone can help, explain, throw a banal example for understanding.
The creation was done like this, in a separate application. But I don't understand how to give the browser the created tim.
models.py
from django.db import models
from django.contrib.auth.models import User
from slugify import slugify
from django.urls import reverse
class BaseModel(models.Model):
objects = models.Manager()
class Meta:
abstract = True
class Profile(BaseModel):
user = models.OneToOneField(
User, on_delete=models.CASCADE, null=True, blank=True
)
nickname = models.CharField(max_length=30, unique=True, null=True)
team = models.ForeignKey('Team', on_delete=models.SET_NULL, blank=True, null=True)
def save(self, *args, **kwargs):
super(self.__class__, self).save(*args, **kwargs)
if self._state.adding is True:
Profile.objects.create()
def __str__(self):
return self.nickname
class Meta:
verbose_name = "Автор"
verbose_name_plural = "Авторы"
class Team(BaseModel):
name = models.CharField('Название', max_length=50)
tag = models.CharField('Тег', max_length=16, unique=True)
slug = models.SlugField(unique=True, blank=True, null=True)
def __str__(self):
return f'{self.name} [{self.tag}]'
def get_absolute_url(self):
return reverse("team_detail", kwargs={"slug": self.slug})
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Team, self).save(*args, **kwargs)
class Meta:
verbose_name = "Команда"
verbose_name_plural = "Команды"
forms.py
from django import forms
from django.contrib.auth.models import User
from django.forms import TextInput, Textarea, FileInput, IntegerField
from django.forms import TextInput, Textarea, FileInput, Select
from .models import *
class CreateTeamForm(forms.ModelForm):
class Meta:
model = Team
fields = {
'name', 'tag', 'slug'
}
views.py
from django.conf import settings
from django.contrib.auth import authenticate, login, get_user_model
from django.http import HttpResponseRedirect, Http404, HttpResponse
from django.shortcuts import render, redirect, resolve_url
from django.utils.http import url_has_allowed_host_and_scheme
from django.views.generic.base import View
from django.views.generic import DetailView, ListView
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.decorators.csrf import csrf_exempt
from .models import *
from .forms import *
# Create your views here.
class CreateTeam(View):
def get(self, request):
form = CreateTeamForm(request.POST)
context = {'form': form}
return render(request, 'team/home.html', context)
def post(self, request):
if request.method == 'POST':
form = CreateTeamForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
return redirect('home')
I'm just learning django, so it's hard to implement everything at once, and I'll be happy to help.
NEW CODE
forms.py
class JoinTeamForm(forms.ModelForm):
key = forms.CharField(label='key', max_length=20)
class Meta:
model = Team
fields = {'key'}
I tried without key = forms.CharField(label='key', max_length=20), but in html {{ form.key }} didn't work.
views.py
class JoinTeam(LoginRequiredMixin, View):
def get(self, request, pk):
print(f'post:{request.POST}, get:{request.GET}')
form = JoinTeamForm(request.POST or None)
team = Team.objects.get(id=pk)
context = {'form': form,
'team': team
}
return render(request, 'team/team_detail.html', context)
def post(self, request, pk):
print(f'post: {request.POST} team_id: {Team.objects.get(id=pk).key}')
profile = request.user.profile
error_msg = 'Неверный код'
if request.method == 'POST':
form = JoinTeamForm(request.POST)
role = Role.objects.get(id=2)
team = Team.objects.get(id=pk)
if form.is_valid():
key = form.save()
if key == team.key:
profile.team = team
profile.role = role
profile.save()
return redirect(team.get_absolute_url())
else:
return HttpResponse(error_msg)
return redirect(team.get_absolute_url())
Could you edit your view to update the user's profile after the team is created?
class CreateTeam(View):
def get(self, request):
form = CreateTeamForm(request.POST)
context = {'form': form}
return render(request, 'team/home.html', context)
def post(self, request):
profile = request.user.profile
if request.method == 'POST':
form = CreateTeamForm(request.POST)
if form.is_valid():
team = form.save()
profile.team = team
profile.save()
return redirect('home')
return redirect('home')
Please note, the way you have this set up is that each profile can only be on one team. If that's your intent, great, but if not you may want to set up a many to many model here so a user can be associated with multiple teams.
Here is my code below. why am I getting an error
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
def __str__(self):
return f'{self.user.username} Profile'
Why is my f-string messing up? It says instance on OneToOneField has no 'username' member?
Here is how I call Profile--code below--signals.py file--
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
So in signals.py >> 'Profile.objects.create(user=instance)' Profile contains no object member...
Why am I getting the Integrity Error despite the fact that I'm checking that the username is unique here:
(I also tried try/expect IntegretyError instead of e.count())
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from slugify import slugify
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
username = models.CharField(max_length=30, blank=True, unique=True) #should be true on signup
name = models.CharField(max_length=30, blank=True)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
email = models.EmailField() #should be true on signup
avatar_url = models.URLField(default="https://image.flaticon.com/icons/png/512/64/64572.png")
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
# if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save(commit=False)
from allauth.account.signals import user_logged_in, password_set, user_signed_up
from django.db.models.signals import post_save
from django.dispatch import receiver, Signal
#receiver(user_logged_in)
def populate_profile(sociallogin, user, **kwargs):
# picture_url = ""
if sociallogin.account.provider == 'github':
user_data = user.socialaccount_set.filter(provider='github')[0].extra_data
print(user_data)
username = user_data['login']
avatar_url = user_data['avatar_url']
email = user_data['email']
name = user_data['name']
bio = user_data['bio']
location = user_data['location']
if sociallogin.account.provider == 'twitter':
user_data = user.socialaccount_set.filter(provider='twitter')[0].extra_data
print(user_data)
username = user_data['screen_name']
avatar_url = user_data['profile_image_url'].replace("_normal", "")
email = user_data['email']
name = user_data['name']
bio = user_data['description']
location = user_data['location']
e = Profile.objects.filter(username=username)
if e.count() > 0:
user.profile.username = slugify(name)
else:
user.profile.username = username
#except IntegrityError:
user.profile.avatar_url = avatar_url
user.profile.email = email
user.profile.name = name
user.profile.bio = bio
user.profile.location = location
user.profile.save()
Well, probably this line of code is the issue:
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
# if created:
Profile.objects.create(user=instance) # <---
Because, every-time user is saved, this signal will be triggered, hence will try to create a profile. Instead, use the commented out code section:
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
Then only if the a user is created, then a profile will be created.
Also I am not sure if the following code will work. Because model's save() method does not have any keyword argument named commit. So it might throw error.
To be honest, you don't need that signal, so you can remove that as well.
I am new to django , I am learning how to extend the user model using the following site:
https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html
I have some doubt in the following model:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
How this line exactly works:
Profile.objects.create(user=instance)
I know post_save will be called after user is created, but I don't understand how the following line is used to store the additional fields.
Profile.objects.create(user=instance)
I am trying to create a profile model for all of my users. I have the following code in which I get one custom field birth_date, but cannot seem to get any of my other custom fields to work:
forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class SignUpForm(UserCreationForm):
birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
class Meta:
model = User
fields = ('username', 'first_name','last_name', 'birth_date','location', 'password1', 'password2', )
models.py:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
views.py
from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .forms import SignUpForm
def home(request):
return HttpResponse('fd')
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
user.refresh_from_db() # load the profile instance created by the signal
user.profile.birth_date = form.cleaned_data.get('birth_date')
user.profile.college = form.cleaned_data.get('college')
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('home')
else:
form = SignUpForm()
return render(request, 'accounts/profile.html', {'form': form})
urls.py
urlpatterns = [
url(r'^register/$', views.signup, name='profile'),
url(r'^home/$', views.home, name='home'),
]
If I were to remove locationfrom forms.py, the form would load properly and allow me to fill it out and upon submission all data, including the custom field birth_date would save. But when I try to add location to the form, I get the following error:
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/forms/models.py", line 262, in __new__
raise FieldError(message)
django.core.exceptions.FieldError: Unknown field(s) (location) specified for User
I am not sure why I cannot add the location field to the form.
Because it's not a field on User. You need to do the same as you have for birth_date - declare it separately in the form class, and save it explicitly to the profile in the view.