Let's get to the problem
I have a page where I want users to fill info about themselves, and i would like to save that data. But I'm getting this error.
IntegrityError at /accounts/profile/edit/1/change-profile/
UNIQUE constraint failed: accounts_user.username
this is my view.py
def change_profile(request, pk):
form = ChangeProfile(request.POST or None)
user_ = request.user
if request.method == "POST":
if form.is_valid():
form.save()
return redirect("/accounts/profile/edit/{}/".format(user_.pk))
args = {'form': form}
return render(request, 'change_profile.html', args)
my models.py
class GradeUser(models.Model):
grade = models.CharField(max_length=20, null=True)
class Country(models.Model):
country = models.CharField(max_length=30, null=True)
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name = 'email address',
max_length=255,
unique=True
)
real_name = models.CharField(max_length=20, blank=True)
username = models.CharField(max_length=40, unique=True, verbose_name='username')
grade = models.ForeignKey(GradeUser, on_delete=models.CASCADE, blank=True, null=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE, blank=True, null=True)
reputation = models.IntegerField(default=0)
image = models.ImageField(upload_to='accounts/media', blank=True)
about_me = models.TextField()
USERNAME_FIELD= 'email'
REQUIRED_FIELDS = ['username']
objects = UserManager()
forms.py
class ChangeProfile(forms.ModelForm):
class Meta:
model = User
fields = ('real_name', 'grade', 'country', 'about_me')
What does exactly go wrong?
Why would it need a user's username?
What should I do with it to save?
You aim to perform an update on your User (that already exists) but here you are creating a whole new user instance with no username attribute and that's what generates the error.
Try this code : it gets your current user and updates it with the info provided from the form.
PS : I did not modify anything about the returns because I dunno what you're doing there but note that you don't need to pass the user pk through the arguments, the user data is already stored in the request object.
def change_profile(request, pk):
form = ChangeProfile()
user_ = request.user
if request.method == "POST":
form = ChangeProfile(request.POST)
if form.is_valid():
user_new_info=form.save(commit=false)
user_.real_name = user_new_info.real_name
user_.grade = user_new_info.grade
user_.country = user_new_info.country
user_.about_me = user_new_info.about_me
user_.save()
return redirect("/accounts/profile/edit/{}/".format(user_.pk))
args = {'form': form}
return render(request, 'change_profile.html', args)
Related
I'm currently processing a payment thing for an online subscription service and in order to get the users info to send this stuff, I have a payment form.
But, for some reason the payment form is not saving to the users account. Everything else actually processes and the only error I can trigger is a 'NOT NULL constraint failed: memberships_usermembership.user_id'
Here's what I have in my view -
#login_required()
def payments(request):
user_membership = get_user_membership(request)
selected_membership = get_selected_membership(request)
form = SubscriptionForm()
if request.method == "POST":
form_data = {
'full_name': request.POST['full_name'],
'email': request.POST['email'],
'phone_number': request.POST['phone_number'],
'country': request.POST['country'],
'postcode': request.POST['postcode'],
'town_or_city': request.POST['town_or_city'],
'street_address1': request.POST['street_address1'],
'street_address2': request.POST['street_address2'],
'county': request.POST['county'],
}
token = request.POST['stripeToken']
form = SubscriptionForm(form_data)
if form.is_valid():
customer = stripe.Customer.retrieve(
user_membership.stripe_customer_id)
customer.source = token
customer.save()
subscription = stripe.Subscription.create(
customer=user_membership.stripe_customer_id,
items=[
{"plan": selected_membership.stripe_plan_id},
]
)
user_membership = get_user_membership(request)
selected_membership = get_selected_membership(request)
user_membership.membership = selected_membership
user_membership.save()
form.save(commit=True)
subscription_id = subscription.id
sub, created = Subscription.objects.get_or_create(
user_membership=user_membership)
sub.stripe_subscription_id = subscription_id
sub.active = True
sub.save()
try:
del request.session['selected_membership_type']
except BaseException:
pass
return render(request, 'memberships/update-success.html')
else:
return redirect(reverse('membership_list'))
context = {
'selected_membership': selected_membership,
'form': form,
}
return render(request, 'memberships/payment.html', context)
When the form.save() is the line above the return(render) line, it will process everything as normal, and the form information just wont save into the DB.
It flashes the NOT NULL error when the form.save() line is where it in in the code above.
Any ideas how to get this working?
Thanks!
EDIT: Here's a link to the entire error in Django - http://dpaste.com/140VD8M
& a screenshot of it too!
Here's my models -
class Membership(models.Model):
membership_type = models.CharField(
choices=MEMBERSHIP_CHOICES,
default='Free',
max_length=30)
price = models.IntegerField(default=15)
description = models.TextField(default="DESCRIPTION")
image_url = models.URLField(max_length=1024, null=True, blank=True)
image = models.ImageField(null=True, blank=True)
stripe_plan_id = models.CharField(max_length=40)
def __str__(self):
return self.membership_type
class UserMembership(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
full_name = models.CharField(max_length=50, null=True, blank=True)
email = models.EmailField(max_length=254, null=True, blank=True)
phone_number = models.CharField(max_length=20, null=True, blank=True)
country = CountryField(blank_label='Country', default="Ireland")
postcode = models.CharField(max_length=20, null=True, blank=True)
town_or_city = models.CharField(max_length=40, null=True, blank=True)
street_address1 = models.CharField(max_length=80, null=True, blank=True)
street_address2 = models.CharField(max_length=80, null=True, blank=True)
county = models.CharField(max_length=80, null=True, blank=True)
stripe_customer_id = models.CharField(max_length=40)
membership = models.ForeignKey(
Membership, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.user.username
def post_save_usermembership_create(
sender, instance, created, *args, **kwargs):
user_membership, created = UserMembership.objects.get_or_create(
user=instance)
if user_membership.stripe_customer_id is None or user_membership.stripe_customer_id == '':
new_customer_id = stripe.Customer.create(email=instance.email)
free_membership = Membership.objects.get(membership_type='Free')
user_membership.stripe_customer_id = new_customer_id['id']
user_membership.membership = free_membership
user_membership.save()
post_save.connect(post_save_usermembership_create,
sender=settings.AUTH_USER_MODEL)
class Subscription(models.Model):
user_membership = models.ForeignKey(
UserMembership, on_delete=models.CASCADE)
stripe_subscription_id = models.CharField(max_length=40)
active = models.BooleanField(default=False)
def __str__(self):
return self.user_membership.user.username
& here's my user membership def -
#login_required()
def get_user_membership(request):
user_membership_qs = UserMembership.objects.filter(user=request.user)
if user_membership_qs.exists():
return user_membership_qs.first()
return None
Instead of collecting all the form fields individually, you should be able to just pass the request.POST to the form like so:
form_data = request.POST
token = request.POST['stripeToken']
form = SubscriptionForm(form_data)
Other than that, without seeing the exact error message, there isn't much more to tell. If you update your question I will update my answer.
EDIT:
Without seeing your model and what get_user_membership() returns, it looks like you are missing a User object in a UserMembership class (but I can't tell without seeing more):
user_membership.user = request.user
Or something like that.
I am trying to save the owner_id that is the same as the Logged In user/Authenticated user. But after I save the AddressBook form,the database saves the owner id with 'Null' value. Can someone help me knowing where am I going wrong.
models.py
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="profile")
mobiles = models.ManyToManyField(Product, blank=True)
class AddressBook(models.Model):
name = models.CharField(max_length=50)
owner = models.ForeignKey(UserProfile, on_delete=models.SET_NULL, null=True)
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
phone_number = models.CharField(validators=[phone_regex], max_length=17) # validators should be a list
line1 = models.CharField(max_length=100)
line2 = models.CharField(max_length=100, blank=True)
city = models.CharField(max_length=25)
state = models.CharField(max_length=25)
postcode = models.CharField(max_length=8)
country = models.CharField(max_length=25)
views.py
#login_required
def address(request):
existing_order = get_user_pending_order(request)
form = AddressBookForm()
context = {
'addressbook': AddressBook.objects.all(),
'form' : form,
'order' : existing_order,
}
return render(request, 'cart/user_address.html', context)
#login_required
def process_payment(request, order_id):
if request.method == 'POST':
form = AddressBookForm(request.POST)
if form.is_valid():
form.save()
return redirect (reverse('update-records', kwargs={'order_id': order_id}))
forms.py
from django import forms
from .models import AddressBook
class AddressBookForm(forms.ModelForm):
ADDRESS_TYPE = (
('Home', 'Home'),
('Work', 'Work'),
)
address_type = forms.ChoiceField(choices=ADDRESS_TYPE, widget=forms.RadioSelect)
class Meta:
model = AddressBook
fields = ['name', 'phone_number', 'line1', 'line2', 'city', 'state', 'postcode', 'country','address_type']
Database
You can save the form with commit=False, set the owner, and then save to the database:
if request.method == 'POST':
form = AddressBookForm(request.POST)
if form.is_valid():
address = form.save(commit=False)
address.owner = request.user.profile
address.save()
When I enter info into my formset, the images gets erased and I'm not able to advance to the next page. No errors appear on the page. Essentially, the form data isn't passing "is_valid". I'm pretty certain that there is something wrong in my view.py.
Models.py
class Testimonial(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
image = VersatileImageField('image_testimonial', upload_to=upload_location, validators=[file_size], null=True, blank=True)
message = models.CharField(max_length=300, default='', null=True, blank=True)
name = models.CharField(max_length=100, default='', null=True, blank=True)
city = models.CharField(max_length=100, default='', null=True, blank=True)
state = models.CharField(max_length=100, default='', null=True, blank=True)
def __str__(self):
return self.author.username
forms.py
class TestimonialForm (forms.ModelForm):
class Meta:
model = Testimonial
fields = ('image', 'message', 'name', 'city', 'state',)
views.py
#login_required(login_url="/accounts/login/")
def testimonials(request):
TestimonialFormSet = modelformset_factory(Testimonial, form=TestimonialForm, extra=3)
if request.method == 'POST':
formset = TestimonialFormSet(request.POST or None, request.FILES or None)
if formset.is_valid():
instances = formset.save(commit=False)
for instance in instances: #for instance in instances.cleaned_data:
instance.author = request.user
fix_orientation(instance.image)
instance.save()
return redirect('/accounts/profile/')
else:
args = {'formset': formset}
return render(request, 'accounts/page6.html', args)
else:
formset = TestimonialFormSet(queryset=Testimonial.objects.filter(author=request.user))
return render(request, 'accounts/page6.html', {'formset': formset})
I had to
a) include {{formset.errors}} in my template to render the error that was preventing submission
b) include {{ form.id }} in the template even though id isn't part of my model. This seems to be an odd quirk of formset, but alas, I can now submit the form.
Shoutout to Daniel Roseman for helping me find the answer!
this me again. I have some trouble with my code. I made a form from ModelForm which have a model with 8 attributes, but i want to user fill only one of them,and one from the system. The one that user fill is okay, but the one filled with system is not working.
models.py
class SeminarProposal(md.Model):
# diisi oleh mahasiswa
fileProposal = models.FileField()
# This is the one is filled with system
proposal = models.OneToOneField(Proposal,
on_delete=models.CASCADE,
related_name="propSid",
unique=True, blank=True, null=True)
masabimbingan = models.BooleanField(default=True)
# disi oleh admin
tanggal = models.DateField(default=timezone.now, blank=True,null=True)
tempat = models.CharField(max_length=30, blank=True, null=True)
# diisi oleh dosen pembimbing
dospemsetuju = models.BooleanField(default=False, blank=True)
# diisi oleh kaprodi
penguji1 = models.ForeignKey(Dosen,
on_delete=models.CASCADE,
related_name="penguji1",
blank=True, null=True)
penguji2 = models.ForeignKey(Dosen,
on_delete=models.CASCADE,
related_name="penguji2",
blank=True, null=True)
def __str__(self):
return "Sidang untuk " + self.proposal.judul
view.py
def daftarSeminar(request):
if request.method == 'POST':
form = FormSeminar(request.POST, request.FILES)
print(request.user)
if form.is_valid():
form.save(commit=False)
form.cleaned_data['proposal']
print(request.user)
prop = Proposal.objects.get(akun=request.user)
form.proposal = prop
print(form.proposal) #to confirm that this is not None
form.save()
return redirect('proposal:bimbingan')
else:
return render(request, 'sidprop.html' , {'oke': 'oke'})
return redirect('proposal:index')
form.py
class FormSeminar(forms.ModelForm):
class Meta:
model = SeminarProposal
fields = ['fileProposal','proposal']
Thanks in advance. Terimakasih.
Instead of changing the form data, get the object from form and change the object's data:
if form.is_valid():
obj = form.save(commit=False)
prop = Proposal.objects.get(akun=request.user)
obj.proposal = prop
obj.save()
return redirect('proposal:bimbingan')
I have a django app with which every registered user can create categories. For the authentication I am using django-all-auth. My models.py looks like this:
class Profile(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.OneToOneField(User, on_delete=models.CASCADE)
create_date = models.DateTimeField('date added', auto_now_add=True)
modify_date = models.DateTimeField('date modified', default=timezone.now)
class Category(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
name = models.CharField(max_length=200, unique=True)
create_date = models.DateTimeField('date added', auto_now_add=True)
modify_date = models.DateTimeField('date modified', default=timezone.now)
On the index page the user can see the created categories and create new ones.
The views.py:
def CategoryView(request):
user = 0
if request.user.is_authenticated():
user = request.user
form = CategoryNameForm()
form.user = user
context = {
'categories': Category.objects.all(),
'form': form,
'user':user,
}
if request.method == 'POST':
form = CategoryNameForm(request.POST)
form.user = user
if form.is_valid():
form.save()
return render(request, 'myapp/index.html',context)
forms.py:
class CategoryNameForm(forms.ModelForm):
class Meta:
model = Category
fields = ('name',)
The authentication works. So I was thinking to just put pass the user field into the form :
class CategoryNameForm(forms.ModelForm):
class Meta:
model = Category
fields = ('name','user',)
hide it and then, just select it via JS since the user is in the context. I was just wondering if there is an easier way. This form.user = user for some reason didn't work, I get a NOT NULL constraint failure
There are couple of ways but here is one:
class CategoryNameForm(forms.ModelForm):
class Meta:
model = Category
fields = ('name',) # take out user you don't need it here
def save(self, **kwargs):
user = kwargs.pop('user')
instance = super(CategoryNameForm, self).save(**kwargs)
instance.user = user
instance.save()
return instance
Then in view:
if form.is_valid():
form.save(user=request.user, commit=False)
Make sure your CategoryView is only accessible by authenticated user. Otherwise you will still get NOT NULL constraint failure for user.