IntegrityError when saving model object second time - python

I have a Post model with OneToOneField to a User model
class Post(models.Model):
user = models.OneToOneField(User)
title = models.CharField(max_length=255)
content = models.TextField()
date = models.DateField(auto_now_add = True)
def __unicode__(self):
return self.title
When I add a new post (using forms), everything is OK. But when I add the second post passing the same user, I get the UNIQUE constraint failed: socnet_post.user_id error.
I use a custom authentication backend:
from django.contrib.auth.models import User
class EmailAuthBackend(object):
def authenticate(self, username=None, password=None):
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Exception goes from the post.save() line:
#login_required
def profile(request, username=None):
context = RequestContext(request)
if not username:
username = request.user.username
user = User.objects.get(username=username)
posts = Post.objects.filter(user=user)
context_dict = {'posts': posts}
if request.method == 'POST':
form = AddPostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.user = request.user
post.save()
add_post_form = AddPostForm()
context_dict['add_post_form'] = add_post_form
return render_to_response('socnet/profile.html', context_dict, context)

It looks like you should use a foreign key instead of the one-to-one field as it's a one-to-many relationship (user can write many articles):
class Post(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=255)
content = models.TextField()
date = models.DateField(auto_now_add = True)
def __unicode__(self):
return self.title

Related

Django foreignkey not getting any user

I am building a Django app. I have customized the User model. My models.py:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from phonenumber_field.modelfields import PhoneNumberField
from phonenumber_field.phonenumber import PhoneNumber
# Create your models here.
class UserManager(BaseUserManager):
def create_user(self, phone_number,username,email=None, password=None):
if not phone_number:
raise ValueError("You must specify your phone number")
if not username:
raise ValueError("You must specify your username")
try:
user = self.model(phone_number= PhoneNumber.from_string(phone_number=phone_number,region="BD").as_national,
username=username,
email=self.normalize_email(email))
except :
user = self.model(phone_number= PhoneNumber.from_string(phone_number=phone_number,region="BD").as_national,
username=username)
user.save(using=self._db)
return user
def create_stuffuser(self, phone_number,username,email,password):
user = self.create_user(phone_number,username,email=email,password=password)
user.staff = True
user.save(using=self._db)
return user
def create_superuser(self, phone_number,username,email,password):
user = self.create_user(phone_number,username,email=email,password=password)
user.staff = True
user.admin= True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
phone_number = PhoneNumberField(unique=True)
username = models.CharField(unique=False,max_length=50)
REQUIRED_FIELDS = ['username']
email = models.EmailField(unique=False)
is_active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
USERNAME_FIELD = 'phone_number'
def get_full_name(self):
return self.username
def get_short_name(self):
return self.username
def get_email(self):
return self.email
def __str__(self):
return str(self.phone_number)
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self,app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
objects = UserManager()
I am logged in but it is throwing error.
My Ticket model:
User = settings.AUTH_USER_MODEL
class Ticket(models.Model):
from_station = models.CharField(max_length=30)
to_station = models.CharField(max_length=30)
purchased_on = models.DateTimeField(default=timezone.now)
travel_on = models.DateTimeField()
customer = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return f"Customer:{self.customer.username},From:{self.from_station},To:{self.to_station},Travel on:{self.travel_on},Purchased on:{self.purchased_on}"
My views.py:
#csrf_protect
#login_required
def buyticket(response):
if response.method == 'POST':
form = Ticket(response.POST)
if form.is_valid():
form.save()
return redirect('main-home-page')
else:
form = Ticket()
return render(response,'main/ticket.html',{'form':form})
The error I got:
Ticket has no customer.
Request Method: GET
Request URL: http://127.0.0.1:8000/ticket/
Django Version: 3.2.4
Exception Type: RelatedObjectDoesNotExist
Exception Value:
Ticket has no customer.
Exception Location: C:\Users\HP\AppData\Local\Programs\Python\Python39\lib\site-packages\django\db\models\fields\related_descriptors.py, line 197, in __get__
Python Executable: C:\Users\HP\AppData\Local\Programs\Python\Python39\python.exe
Python Version: 3.9.2
A user can have multiple tickets. But it is not taking any user. Whenever I am trying to go to ticket route it calls me to login. I do but then it throws this error.
This error shows to you cause You declare the from equal to model
in :
else:
form = Ticket()
You should create another file called forms.py in the app
and do something like that
from .models import Ticket
from django.forms import ModelForm
class TicketForm(ModelForm):
class Meta:
model = Ticket
fields = '__all__
and in views
from .forms import TicketForm
def buyticket(response):
form = TicketForm()
if response.method == 'POST':
if form.is_valid():
form.save()
return redirect('main-home-page')
else:
form = TicketForm()
return render(response,'main/ticket.html',{'form':form})
You can get more info in the docs

Django don't login after change password use Abstractuser

i custom user use abstractuser
class User(AbstractUser):
create_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
name=models.CharField(max_length=50)
phone=models.CharField(max_length=15)
position=models.CharField(max_length=30)
but when i change password user in adminpage
i can't login with login function
class LoginClass(View):
def get(self,request):
if not request.user.is_authenticated:
return render(request, 'new_template/signin.html')
else:
return redirect('user:view_camera')
def post(self,request):
username1 = request.POST.get('username1')
password1= request.POST.get('password1')
my_user = authenticate(username=username1,password=password1)
if my_user is None:
return redirect('/')
login(request, my_user)
next_url = request.GET.get('next')
if next_url is None:
return redirect('user:view_camera')
else:
return redirect(next_url)
password = 12345678
user = User.objects.get(pk=pk)
user.set_password(str(password))
user.save()
######-######
user.set_password only str value

How can i set permission on url

I am new on Django,
I have implemented a valid form and now I want to set permission on URL.
When a form is submitted, then it redirects me to this URL
http://127.0.0.1:8000/success/
Without submitting a form I can manually type the name of the URL http://127.0.0.1:8000/success/ and it will take me to the same page.
How can I set permission on "success" url, so that user can not manually view the page unless the form is valid and submitted?
Do I need a decorator for this?
Model:
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,blank=True,null=True)
profile_pic = models.ImageField(upload_to='ProfilePicture/', default="ProfilePicture/avatar.png", blank=True)
phone = models.IntegerField(default='0', blank=True)
email = models.EmailField(blank=True)
date_of_birth = models.CharField(max_length=50, blank=True)
address = models.TextField(blank=True)
date = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'Profile'
verbose_name_plural = 'Profiles'
ordering = ['-date']
'''Method to filter database results'''
def __str__(self):
return self.user.username
class CotCode(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
cot_code = models.IntegerField(default='0', blank=True)
date = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'CotCode'
verbose_name_plural = 'CotCode'
ordering = ['-date']
def __str__(self):
return self.user.username
Url:
path('cot/', TransferCOTView, name='transfer_cot'),
path('success/', SuccessfulView, name='successful_trans'),
Views:
#login_required
def TransferCOTView(request):
form = CotCodeForm(request.POST)
if request.method == "POST":
if form.is_valid():
cot_code = form.cleaned_data.get('cot_code')
try:
match = CotCode.objects.get(cot_code=cot_code)
return redirect('site:successful_trans')
except CotCode.DoesNotExist:
messages.info(request, "Wrong code")
else:
form = CotCodeForm()
context = {
'form':form,
}
return render(request, 'transfer_cotcode.html', context)
#login_required
def SuccessfulView(request):
return render(request, 'successful_transfer.html')
A simple option would be to set a session variable informing that the form was posted and valid and check it before displaying the success page. See session examples here https://docs.djangoproject.com/en/3.1/topics/http/sessions/#examples
e.g.
def formview(request):
# process form
request.session["form_filled"] = True
# redirect to success
def success(request):
if not request.session.get("form-filled"):
raise Http404("Form not filled")
del request.session["form_filled"] # success view visible once after form is filled
# return view template
You can also check if the user has COT code filled in the success view.
def SuccessfulView(request):
cot_code_exists = CotCode.objects.filter(user=request.user).count()
if not cot_code_exists:
raise Http404("Cot code does not exist for user")
return render(request, 'successful_transfer.html')

Trying to link two models with a ForeignKey but get the error "IntegrityError NOT NULL"

I have a model where a user posts a job vacancy, then other users can submit applications. The submit application model is called 'CandidatesSubmission' & pulls the 'title' from a different app/model 'JobPosts'.
I can add submit applications through the ADMIN page fine, but when trying to do so with a form I get "IntegrityError NOT NULL constraint failed: candidates_candidatessubmission.title_id."
I believe that I'm missing something in my Views.py that essentially says "use the title of job vacancy as the title field.
I have tried adding null=True, blank=False but which stops the error but the title isn't saved to the database.
Any suggestions on what I'm doing wrong would be great. Thank you
models.py
class CandidatesSubmission(models.Model):
title = models.ForeignKey('jobs.JobsPost', on_delete=models.CASCADE)
Fee = models.CharField(max_length=50, null=False, blank=False)
CandidateFirstName = models.CharField(max_length=50, null=True, blank=False)
CandidateSecondName = models.CharField(max_length=50, null=True, blank=False)
created = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.db.models import Q
from django.http import HttpResponseNotFound
from jobs.models import JobsPost
from candidates.models import CandidatesSubmission
from candidates.forms import CreateCandidatePostForm
from account.models import Account
from operator import attrgetter
# Create your views here.
def submit_candidates_view(request, slug):
context = {}
user = request.user
if not user.is_authenticated:
return redirect('must_authenticate')
form = CreateCandidatePostForm(request.POST or None, request.FILES or None)
if form.is_valid():
obj = form.save(commit=False)
author = Account.objects.filter(email=user.email).first()
obj.author = author
obj.save()
form = CreateCandidatePostForm()
context['form'] = form
accounts = CandidatesSubmission.objects.all()
context['accounts'] = accounts
return render(request, 'candidates/submit_candidates.html', context)
def response_view(request):
context = {}
accounts = CandidatesSubmission.objects.all()
context['accounts'] = accounts
return render(request, "candidates/response.html", context)
forms.py
from django import forms
from candidates.models import CandidatesSubmission
class CreateCandidatePostForm(forms.ModelForm):
class Meta:
model = CandidatesSubmission
fields = ['Fee', 'CandidateFirstName', 'CandidateSecondName']
def save(self, commit=True):
submission_post = self.instance
submission_post.Fee = self.cleaned_data['Fee']
submission_post.CandidateFirstName = self.cleaned_data['CandidateFirstName']
submission_post.CandidateSecondName = self.cleaned_data['CandidateSecondName']
if commit:
submission_post.save()
return submission_post
if you have "current" title, so your slug might store it, so you can use it like that.
def submit_candidates_view(request, slug):
context = {}
user = request.user
if not user.is_authenticated:
return redirect('must_authenticate')
form = CreateCandidatePostForm(post_slug=slug, request.POST or None, request.FILES or None)
if form.is_valid():
obj = form.save(commit=False)
author = Account.objects.filter(email=user.email).first()
obj.author = author
obj.save()
form = CreateCandidatePostForm()
context['form'] = form
accounts = CandidatesSubmission.objects.all()
context['accounts'] = accounts
return render(request, 'candidates/submit_candidates.html', context)
in your forms.py we replace __init__ method to receive slug of your title
class CreateCandidatePostForm(forms.ModelForm):
class Meta:
model = CandidatesSubmission
fields = ['Fee', 'CandidateFirstName', 'CandidateSecondName']
def __init__(self, *args, **kwargs):
self.post_slug = kwargs.pop("post_slug", None)
super().__init__(*args, **kwargs)
def save(self, commit=True):
submission_post = self.instance
submission_post.title = JobsPost.objects.get(slug=self.post_slug)
if commit:
submission_post.save()
return submission_post

Django get form with data from the database

I am trying to create a form that allows users to edit their profile data. As such I want to have the most recent data from the database be displayed when the user goes to edit the form. Heres what I have so far:
# models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
location = models.CharField(max_length=30, blank=True)
birthdate = models.DateField(null=True, blank=True)
def __str__(self):
return self.user.username
# forms.py
class EditProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['location', 'birthdate']
# views.py
class EditProfileFormView(View):
form_class = EditProfileForm
template_name = 'forums/edit-profile.html'
def get(self, request, username):
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
raise Http404('The User "' + username + '" could not be found.')
if (not request.user.is_authenticated):
return HttpResponseForbidden()
elif (user.id is not request.user.id):
return HttpResponseForbidden()
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
Setting the form to form_class(None) is what gives me an empty form, however dropping user.profile in the same spot gives me an error 'Profile' object has no attribute 'get'
Try populating the form with an instance
form = self.form_class(instance=user.profile)
Note: this would probably be easier with a standard UpdateView

Categories