null value in column "job_id" violates not-null constraint - python

I'm trying to upload a pdf file but I keep getting an integrity error, when I try to submit the pdf file, it looks like I have some blank space in the DB which I don't know, may someone please help me! The error is:
IntegrityError at /posts/resume/
null value in column "job_id" violates not-null constraint
models.py
class Jobs(models.Model):
title = models.CharField(max_length=80)
jobs_type = models.CharField(max_length=80, choices=JOB_CHOICES)
description = models.TextField()
requirements = models.TextField()
posted_date = models.DateTimeField(auto_now_add=True)
start_date = models.DateField()
deadline = models.DateField()
link = models.URLField()
slug = models.SlugField(max_length=150)
contacts = models.CharField(max_length=80)
tags = TaggableManager()
class Meta:
ordering = ('-posted_date',)
class Application(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL, related_name="application",
on_delete=models.CASCADE)
job = models.ForeignKey(Jobs, on_delete=models.CASCADE)
professional_summary = models.TextField()
resume = models.CharField(max_length=150)
uploaded_at = models.DateTimeField(auto_now_add=True)
form.py
class ApplicationForm(forms.ModelForm):
resume = forms.FileField(widget=forms.FileInput(attrs={'onchange': 'uploadPreview(this)'}))
oss_resume = forms.CharField (widget=forms.HiddenInput(), required=False)
class Meta:
model = Application
fields = ('professional_summary', 'resume', )
views.py
class CreateApplicationView(LoginRequiredMixin, CreateView):
form_class = ApplicationForm
model = Application
message = _("Your Event has been created.")
success_url = reverse_lazy('posts:list_jobs')
def __init__(self, **kwargs):
self.object=None
super().__init__(**kwargs)
def form_valid(self, form):
resume = form.cleaned_data['oss_resume']
form.instance.user = self.request.user
submit = form.save()
submit.user= self.request.user
if not resume:
return ('posts/no_resume.html')
else:
submit.save()
def get_success_url(self):
messages.success(self.request, self.message)
return reverse('posts:list_events')
def get_object(self):
resume = kwargs.get('resume')
return Application.objects.get(resume=resume)
urls.py
url(r'^list-jobs/$', JobsListView.as_view(), name='list_jobs'),
url(r'^resume/$', CreateApplicationView.as_view(), name='resume'),
the results is
IntegrityError at /posts/resume/
null value in column "job_id" violates not-null constraint
DETAIL: Failing row contains (7, first job , processing.pdf, 2019-07-10 11:40:06.873356+00, null, null).

Your Application model has a ForeignKey to Jobs model (which I think should be just Job, but that's another matter), but it is not nullable/blank. It seems to me your view does not provide a Jobs instance to the Application instance that's being created with the PDF upload, hence the error.
Update:
One way of doing this would be to add null=True, blank=True to your job field declaration on the Application model. However, this doesn't sound like a good solution, as an application should be associated to a job. So you need to allow the user to pick the job that he's applying to in the Application form or automatically assign that job to the application when you process the form submission in the CreateApplicationView.
Update 2:
In your ApplicationForm, try to do this:
class ApplicationForm(forms.ModelForm):
resume = forms.FileField(widget=forms.FileInput(attrs={'onchange': 'uploadPreview(this)'}))
oss_resume = forms.CharField(widget=forms.HiddenInput(), required=False)
job = forms.ModelChoiceField(queryset=Jobs.objects.all())
class Meta:
model = Application
fields = ('professional_summary', 'resume', 'job')
I've added the field in the form for the person to pick the Job he/she's applying for. This should fix the error or push you in the right direction.

Related

Django Form Can't Filter Foreign Key on Dropdown

Edit: Rewrote Description for clarity
I have a "CustomUser" class that I got from an all-auth tutorial (Django All-Auth Tutorial) and I have user as a foreign key in each model, which works as intended, only showing records pertaining to the current logged in user to that specific user.
For example:
EDUCATION MODEL (Works Correctly Here)
class Education(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
EducationInstitutionName = models.CharField(verbose_name=_('Institution Name'), max_length=100, default=None)
EducationLevel = models.CharField(verbose_name=_('Education Level'), choices=EDUCATIONLEVEL, max_length=100, default=None)
EducationStartDate = models.DateField(verbose_name=_('Education Start Date'), default=None)
EducationEndDate = models.DateField(verbose_name=_('Education End Date'), default=None)
EducationCaoCode = models.CharField(choices=CAO_CODE, max_length=100, default=None)
EducationDesc = models.CharField(verbose_name=_('Education Description'), max_length=250, default=None)
def __str__(self):
return self.EducationInstitutionName
This works perfectly and I am achieving what is needed.
The issue arises when I have a table comprised of Foreign Keys which is the focal point of my application which takes the constituent parts of a CV and allows you to combine them to make a CV of interchangable sections.
CV MODEL (Only model I have which is composed of Foreign Keys)
class Cv(models.Model):
user = models.ForeignKey(
CustomUser,
on_delete=models.CASCADE,
)
CvName = models.CharField(verbose_name=_('CvName'), max_length=100, default=None)
CvEducation = models.ForeignKey(Education, on_delete=models.CASCADE)
CvSkills = models.ForeignKey(Skills, on_delete=models.CASCADE)
CvWorkExperience = models.ForeignKey(WorkExperience, on_delete=models.CASCADE)
def __str__(self):
return self.CvName
CV FORM
This is where I'm hitting the issue - I want to filter the fields to only show records of Education, Skills and Work Experience for the current user - at the moment the dropdown shows every record in existence for the Education, Skills and Work Experience models rather than those ONLY pertaining to the current logged in user.
class CvForm(forms.ModelForm):
class Meta:
model = Cv
fields = ('CvName', 'CvEducation', 'CvSkills', 'CvWorkExperience')
# TRYING TO FILTER BY CURRENT USER
def __init__(self, user, *args, **kwargs):
super(CvForm, self).__init__(*args, **kwargs)
print(user)
self.fields['CvEducation'].queryset = Education.objects.filter(user=user)
self.fields['CvSkills'].queryset = Education.objects.filter(user=user)
self.fields['CvWorkExperience'].queryset = Education.objects.filter(user=user)
def save(self, commit=True):
cv = super(CvForm, self).save(commit=False)
cv.user = self.request.user
cv.CvName = self.cleaned_data['CvName']
cv.CvEducation = self.cleaned_data['CvEducation']
cv.CvSkills = self.cleaned_data['CvSkills']
cv.CvWorkExperience = self.cleaned_data['CvWorkExperience']
cv.save()
return cv
CV LIST VIEW (This - correctly - only shows completed CV records associated with the current logged in user)
class CvList(ListView):
model = Cv
fields = ['CvName', 'CvEducation', 'CvSkills', 'CvWorkExperience']
success_url = reverse_lazy('Cv_list')
def get_queryset(self):
user_ids = CustomUser.objects.filter(username=self.request.user).values_list('id', flat=True)
if user_ids:
for uid in user_ids:
return Cv.objects.filter(user__id=uid)
else:
return Cv.objects.all()
CV CREATE VIEW
class CvCreate(CreateView):
model = Cv
fields = ['CvName', 'CvEducation', 'CvSkills', 'CvWorkExperience']
success_url = reverse_lazy('Cv_list')
def form_valid(self, form):
form.instance.user = self.request.user
return super(CvCreate, self).form_valid(form)
def get_queryset(self):
user_ids = CustomUser.objects.filter(username=self.request.user).values_list('id', flat=True)
if user_ids:
for uid in user_ids:
return Cv.objects.filter(user__id=uid)
else:
return Cv.objects.all()
This gives me...
Dropdown showing the whole Education table rather than filtering by Current User
In this image as I'm logged in as John Doe I should not be able to see the record - "James Edu" as that is associated with a different user James.
This occurs in all three of the fields I have with Foreign Keys - CvEducation, CvSkills and CvWorkExperience
Fixed eventually (in a very roundabout way):
FORMS INIT METHOD
def __init__(self, *args, **kwargs):
initial_arguments = kwargs.get('initial', None)
initial_arguments_list = list(initial_arguments.values())
user_id = initial_arguments_list[0]
super(CvForm, self).__init__(*args, **kwargs)
self.fields['CvEducation'].queryset = Education.objects.filter(user__id=user_id)
self.fields['CvSkills'].queryset = Skills.objects.filter(user__id=user_id)
self.fields['CvWorkExperience'].queryset = WorkExperience.objects.filter(user__id=user_id)
CREATE VIEW
class CvCreate(CreateView):
model = Cv
success_url = reverse_lazy('Cv_list')
form_class = CvForm
exclude = ['user']
def get_initial(self):
self.initial.update({ 'created_by': self.request.user.id })
return self.initial

Django 3 - Making Model's FK Dropdown Display Current User's Data Only

I'm creating my first app with Django and still have a lot to learn, but right now I am completely stuck and need some help. I have a model for Customers and Tickets. I have it so different users can save new customers/tickets and only view their data from the dashboard once logged in. However, when creating a new ticket, there is a dropdown option to select customer for the ticket - and the current user is able to see every users customers.
Here is the code, I'll share more code if needed, but I think this covers what I have going on...
forms.py
class TicketForm(ModelForm):
class Meta:
model = Ticket
fields = ['number', 'customer','date_created','work_description','mechanics','status']
views.py
def createTickets(request):
form = TicketForm()
if request.method == 'POST':
form = TicketForm(request.POST)
if form.is_valid():
newticket = form.save(commit=False)
newticket.shopowner = request.user
newticket.save()
return redirect('tickets')
context = {
'form': form
}
return render(request, 'createticket.html', context)
models.py
class Ticket(models.Model):
def default_number():
no = Ticket.objects.count()
return no + 1
shopowner = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
number = models.CharField(max_length=30, unique=True, default= default_number)
customer = models.ForeignKey(Customer, default=1, on_delete= models.SET_DEFAULT, blank=True)
date_created = models.DateField(default=timezone.now)
work_description = models.TextField(verbose_name="Service Details: ")
mechanics = models.ForeignKey(Mechanic, default=1, on_delete=models.DO_NOTHING, blank=True, verbose_name="Mechanic")
status = models.BooleanField(default=True, verbose_name="Open Ticket")
class Meta:
verbose_name_plural = "Tickets"
I need the Customer foreignkey to only display customers of the current user (or 'shopowner') - same thing for mechanic and eventually vehicle but I can figure those out once I know how to get the customer input to display the correct data.
You'll need to customize your form a bit, in order to modify the queryset for that particular field. We also need to pass a user from the view:
forms.py
class TicketForm(ModelForm):
class Meta:
model = Ticket
fields = ['number', 'customer', 'date_created', 'work_description', 'mechanics', 'status']
def __init__(self, user=None, *args, **kwargs):
super().__init__(*args, **kwargs)
if user:
self.fields['customer'].queryset = Customer.objects.filter(shopowner=user)
views.py
def createTickets(request):
form = TicketForm(user=request.user)
# ...
Exactly how you define the queryset is going to depend on how you've defined the relationship between Customer and Shopowner, but this should give you the right approach.

Django Inline form validation ignored partly filled form

I have got the code from https://github.com/adandan01/mybook, the code is working fine, even when I have updated it to Django 2. It's very simple project for adding a person in a form, and his/her relatives in the inline form. Everything works but when I add a relative name and forget to add his relationship, and submitted the form, unfortunately, that record will not pass the validation but will give no error messages as well. Django will ignore the entire record. For example, the record for Hawra in the image, will not be saved and Django will remove it. For this simple App there are only two fields to be filled (name and relationship), but I'm working on app with 8 fields, and it will be difficult to lose the data. is there any way to make django do the validation in the formset/subform as long as any fields have data and will ask the user to fill all required fields?
models.py:
class Profile(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
created_date = models.DateTimeField(default=timezone.now)
def get_absolute_url(self):
return reverse('profile-update', kwargs={'pk': self.pk})
def __unicode__(self):
return "%s %s" % (self.first_name, self.last_name)
class FamilyMember(models.Model):
profile = models.ForeignKey(Profile, on_delete=models.PROTECT)
name = models.CharField(max_length=100)
relationship = models.CharField(max_length=100)
form.py
class ProfileForm(ModelForm):
class Meta:
model = Profile
exclude = ()
class FamilyMemberForm(ModelForm):
class Meta:
model = FamilyMember
exclude = ()
FamilyMemberFormSet = inlineformset_factory(Profile, FamilyMember,
form=FamilyMemberForm, extra=1)
views.py
class ProfileCreate(CreateView):
model = Profile
fields = ['first_name', 'last_name']
class ProfileFamilyMemberCreate(CreateView):
model = Profile
fields = ['first_name', 'last_name']
success_url = reverse_lazy('profile-list')
def get_context_data(self, **kwargs):
data = super(ProfileFamilyMemberCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['familymembers'] = FamilyMemberFormSet(self.request.POST)
else:
data['familymembers'] = FamilyMemberFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
familymembers = context['familymembers']
with transaction.atomic():
self.object = form.save()
if familymembers.is_valid():
familymembers.instance = self.object
familymembers.save()
return super(ProfileFamilyMemberCreate, self).form_valid(form)
I found the solution here django inline_formset - form.empty_permitted = False doesn't work
I had to add the following code before if (familymembers.is_valid():...) in the create and update class, so, now Django will show the error if I entered data in the Name field only and will tell me the Relationship field is required.
if familymembers.is_valid() == False:
return self.render_to_response(self.get_context_data(form=form,familymembers=familymembers ))

Can't edit but can add new inline in Django admin

Here are my models
class Note():
note = models.TextField(null=False, blank=False, editable=True)
user = models.ForeignKey(to=User, null=True, blank=True)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")
And an inline I created this model to incorporate in any admin is below
class NoteInline(GenericTabularInline):
model = Note
extra = 0
What I need here is, I want to see all the current notes but don't want the logged in user to edit them. At the moment user can edit old and add new. So here is what I did,
class NoteInline(GenericTabularInline):
model = Note
extra = 0
def get_readonly_fields(self, request, obj=None):
if obj and 'change' in request.resolver_match.url_name:
return ['note', 'user', ]
else:
return []
But now if user adds new note he sees a disabled (not editable) note text ares. However user can see old fields not editable.
How to implement this functionality?
I am having the same inquiry.
However, I do not care if the fields in the inline are "read only" or not. I just do not want them changed once they are created.
For this purpose, I created a NoteForm in forms.py which raises a validation error if the instance has changed while it has initial data:
class NoteForm(forms.ModelForm):
def clean(self):
if self.has_changed() and self.initial:
raise ValidationError(
'You cannot change this inline',
code='Forbidden'
)
return super().clean()
class Meta(object):
model = Note
fields='__all__'
admin.py:
class NoteInline(GenericTabularInline):
model = Note
extra = 0
form = NoteForm

Django Twitter clone. How to restrict user from liking a tweet more than once?

I'm not sure where to start. Right now, the user can press like as many times they want and it'll just add up the total likes for that tweet.
models.py
class Howl(models.Model):
author = models.ForeignKey(User, null=True)
content = models.CharField(max_length=150)
published_date = models.DateTimeField(default=timezone.now)
like_count = models.IntegerField(default=0)
rehowl_count = models.IntegerField(default=0)
def get_absolute_url(self):
return reverse('howl:index')
def __str__(self):
return self.content
views.py
class HowlLike(UpdateView):
model = Howl
fields = []
def form_valid(self, form):
instance = form.save(commit=False)
instance.like_count += 1
instance.save()
return redirect('howl:index')
Django Twitter clone. How to restrict user from liking a tweet more than once?
As well as tracking how many Likes a post has, you'll probably also want to track who has "Liked" each post. You can solve both of these problems by creating a joining table Likes with a unique key on User and Howl.
The unique key will prevent any User from doing duplicate likes.
You can do this in Django with a ManyToManyField, note that since this means adding a second User relationship to Howl, we need to disambiguate the relationship by providing a related_name
Eg:
class Howl(models.Model):
author = models.ForeignKey(User, null=True, related_name='howls_authored')
liked_by = models.ManyToManyField(User, through='Like')
# ...rest of class as above
class Like(models.Model):
user = models.ForeignKey(User)
howl = models.ForeignKey(Howl)
class Meta:
unique_together = (('user', 'howl'))
like_count count then becomes redundant, since you can use Howl.liked_by.count() instead.
The other benefit of this is that it allows you to store information about the Like - eg when it was added.
An idea could be adding a column to your table named likers and before incrementing like_counts check if the models.likers contains the new liker or not. If not increment the likes, if yes don't.
Changed liked_count in my models.py to
liked_by = models.ManyToManyField(User, related_name="likes")
views.py
class HowlLike(UpdateView):
model = Howl
fields = []
def form_valid(self, form):
instance = form.save(commit=False)
instance.liked_by.add(self.request.user)
instance.like_count = instance.liked_by.count()
instance.save()
return redirect('howl:index')
index.html
{{howl.liked_by.count}}

Categories

Resources