saving foreignkey instances in the createview in views.py - django

I've a models called job, application, attachments. when a job is already created an a user wants to apply for the job I get an integrity error that says null value in column "job_id" violates not-null constraint
If I add job in the fields part of class Meta of ApplicationForm everything runs successful but when the user select the job he whats to apply he is forced to select again the job to fill in the job field,
So I want is to automatically add the job field to be added in createview in views.py
here is my code
models.py
class Application(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='applied_jobs',
null=True, on_delete=models.SET_NULL)
job = models.ForeignKey(Job, related_name='applications', on_delete=models.CASCADE)
career_briefing = models.CharField(max_length=250, null=True)
class Attachments(models.Model):
application = models.ForeignKey(Application, related_name='attachments', on_delete=models.CASCADE)
cv = models.CharField(max_length=150, null=True)
form.py
class ApplicationForm(forms.ModelForm):
cvs = forms.CharField(max_length=6000, widget=forms.HiddenInput(), required=False)
class Meta:
model = Application
fields = ('career_briefing',)
views.py
class ApplicationCreateView(LoginRequiredMixin, CreateView):
model = Application
form_class = ApplicationForm
message = _("succesfuly applied")
template_name = 'jobs/application_form.html'
message = _("successful")
def form_valid(self, form):
cvs = form.cleaned_data['cvs']
form.instance.user = self.request.user
form.instance.job = self.kwargs.get('pk')
apply = form.save(commit=False)
apply.job = self.kwargs.get('pk')
apply.user = self.request.user
apply.save()
doc = Attachments(cv=cvs)
doc.application = apply
doc.save()
return super(ApplicationCreateView, self).form_valid(form)
def get_success_url(self):
messages.success(self.request, self.message)
return reverse("jobs:list")
urls.py
urlpatterns = [
....
url(r'^details/(?P<pk>\d+)/$', JobDetailView.as_view(), name='detail'),
url(r'^details/apply/$', ApplicationCreateView.as_view(), name='apply'),
.....
]
What I expect is that a user submits the application form successful but i get an integrity error " null value in column "job_id" violates not-null constraint ",
For me I think the job instance is not saved ,if this is the real problem may someone please show me how to solve it,
If that's not the problem may someone help me out with this
thanks in advance

Related

Autofill my author field with foreign key

I am trying to autofill my user foreign key in my note project with authentication in django. I tried, but it's not working and asking that owner is required field. Please, help! Thanks in an advance.
views.py
#login_required(login_url='login')
def index(request):
tasks = Task.objects.filter(owner=request.user)
form = TaskForm()
if request.method=='POST':
form = TaskForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.owner = request.user
instance.save()
context = {
'tasks':tasks,
'form':form,
}
return render(request, 'list.html',context)
models.py
class Task(models.Model):
title = models.CharField(max_length=200)
completed = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
def __str__(self):
return self.title
Since you fill in the owner yourself, it makes no sense to specify the owner as a form field. You thus should exclude it, and let this be handled by the view. The form thus looks like:
class TaskForm(forms.ModelForm):
class Meta:
model = Task
exclude = ['owner']
If no ModelForm will need to specify the owner, you can mark the field as non-editable:
class Task(models.Model):
# …
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
editable=False
)
# …

Django ModelChoiceField Issue

I've got the following Situation, I have a rather large legacy model (which works nonetheless well) and need one of its fields as a distinct dropdown for one of my forms:
Legacy Table:
class SummaryView(models.Model):
...
Period = models.CharField(db_column='Period', max_length=10, blank=True, null=True)
...
def __str__(self):
return self.Period
class Meta:
managed = False # Created from a view. Don't remove.
db_table = 'MC_AUT_SummaryView'
Internal Model:
class BillCycle(models.Model):
...
Name = models.CharField(max_length=100, verbose_name='Name')
Period = models.CharField(max_length=10, null=True, blank=True)
Version = models.FloatField(verbose_name='Version', default=1.0)
Type = models.CharField(max_length=100, verbose_name='Type', choices=billcycle_type_choices)
Association = models.ForeignKey(BillCycleAssociation, on_delete=models.DO_NOTHING)
...
def __str__(self):
return self.Name
Since I don't want to connect them via a Foreign Key (as the SummaryView is not managed by Django) I tried a solution which I already used quite a few times. In my forms I create a ModelChoiceField which points to my Legacy Model:
class BillcycleModelForm(forms.ModelForm):
period_tmp = forms.ModelChoiceField(queryset=SummaryView.objects.values_list('Period', flat=True).distinct(),
required=False, label='Period')
....
class Meta:
model = BillCycle
fields = ['Name', 'Type', 'Association', 'period_tmp']
And in my view I try to over-write the Period Field from my internal Model with users form input:
def billcycle_create(request, template_name='XXX'):
form = BillcycleModelForm(request.POST or None)
data = request.POST.copy()
username = request.user
print("Data:")
print(data)
if form.is_valid():
initial_obj = form.save(commit=False)
initial_obj.ModifiedBy = username
initial_obj.Period = form.cleaned_data['period_tmp']
initial_obj.Status = 'Creating...'
print("initial object:")
print(initial_obj)
form.save()
....
So far so good:
Drop Down is rendered correctly
In my print Statement in the View ("data") I see that the desired infos are there:
'Type': ['Create/Delta'], 'Association': ['CP'], 'period_tmp': ['2019-12']
Still I get a Select a valid choice. That choice is not one of the available choices. Error in the forms. Any ideas??

Django Rest Framework - How to set the current_user when POST

I have just followed a small tutorial using DRF, but I can't figure how to like my model to his user when POSTing a new object
this is my model :
# Create your models here.
class Project(models.Model):
# project title
title = models.CharField(max_length=255, null=False)
# subtitle
subtitle = models.CharField(max_length=255, null=False)
#######
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
and so my serializer
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = ("id", "title", "subtitle", "user_id")
so, now in the view I have access to the current_user with this :
request.user
class ListProjectsView(generics.ListCreateAPIView):
authentication_classes = [authentication.TokenAuthentication]
queryset = Project.objects.all()
serializer_class = ProjectSerializer
def list(self, request):
queryset = Project.objects.filter(user_id=request.user.id)
serializer = ProjectSerializer(queryset, many=True)
return Response(serializer.data)
[...]
def create(self, request, pk = None):
return super(ListProjectsView, self).create(request, pk = None)
I suppose there is a way to passe the request.user is the create in order to allow my Project.user_id to be filled ?
Whatever I'm doing, I can't manage to set the user, and i get the
django.db.utils.IntegrityError: null value in column "user_id" violates not-null constraint error
Any idea?
Thanks!
Try to override with following method. Everytime PUT/PATCH/CREATE operation is performed following method is called. This is the good way to pass the current user.
def perform_create(self, serializer):
serializer.save(user = self.request.user)
class Project(models.Model):
# project title
title = models.CharField(max_length=255, null=False)
# subtitle
subtitle = models.CharField(max_length=255, null=False)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
okay so you have FK user but try to access it with the user_id = request.user.id
Just call
queryset = Project.objects.filter(user=request.user)
queryset = Project.objects.filter (user_id=request.user.id)
if you want to match the id you should put two __
like so user__id = request.user.id but I dont see any sence making it.

Django save multiple foreign keys to database with multiple upload

I am a newbie in Django and I am looking for the best workaround on how to deal with this problem.
I have these 3 Models:
class Rigs(models.Model):
name = models.CharField(max_length=30)
featured_img = models.ImageField(upload_to='images/')
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Gallery(models.Model):
rigs = models.ForeignKey(Rigs, on_delete=models.CASCADE, related_name='galleries')
file = models.ImageField(upload_to='images/')
def __str__(self):
return self.name
class Specs(models.Model):
cpu = models.CharField(max_length=50)
motherboard = models.CharField(max_length=50)
rigs = models.ForeignKey(Rigs, on_delete=models.CASCADE)
def __str__(self):
return self.cpu
I am using this library for the multi-uploading of images (https://github.com/Chive/django-multiupload), so basically I structured my Forms similar to what the document states:
class SpecsForm(forms.ModelForm):
class Meta:
model = Specs
fields = ('rigs', 'motherboard')
class RigForm(forms.ModelForm):
class Meta:
model = Rigs
fields = ('name','featured_img')
gallery_image = MultiMediaField(
min_num=1,
max_num=3,
max_file_size=1024*1024*5,
media_type='image'
)
def save(self, commit=True):
instance = super(RigForm, self).save(commit)
for each in self.cleaned_data['gallery_image']:
Gallery.objects.create(file=each, rigs=instance)
return instance
As well as my Views:
class newrig(CreateView):
model = Rigs
form_class = RigForm
template_name = 'flexrigapp/newrig.html'
success_url = '?success'
My problem is that I couldn't figure out how to include the SpecsForm on my HTML Form as well as save it on my database with the correct Foreign Key.
I have already tried transferring this one on my views with some changes but still no good.
def save(self, commit=True):
instance = super(RigForm, self).save(commit)
for each in self.cleaned_data['gallery_image']:
Gallery.objects.create(file=each, rigs=instance)
return instance
Also, I tried a function based views instead of class based but the problem is that the multi-uploading validation doesn't work on this approach of mine or maybe my code is not correct.
The expected result is that data should be saved on its respective databases (Rigs, Specs, Gallery) with the proper Foreign key on the Specs and Gallery. Right now, I can only save the Rigs and Gallery.
This is Django 2.2.4, by the way.
UPDATE
I tried updating my Views to Function-Based View just like what #dirkgroten suggested.
def newrig(request):
if request.method == 'POST':
rig_form = RigForm(request.POST, request.FILES, prefix="rigs")
specs_form = SpecsForm(request.POST, prefix="specs")
if rig_form.is_valid() and specs_form.is_valid():
rigs = rig_form.save()
specs = specs_form.save(commit=False)
specs.rigs = rigs
specs.save()
return HttpResponseRedirect("?success")
else:
rig_form = RigForm(prefix="rigs")
specs_form = SpecsForm(prefix="specs")
return render(request, "flexrigapp/newrig.html", {'rig_form': rig_form,'specs_form': specs_form,})
No data is being saved on the database now. No error logs.

How to filter a (or all) joined table's rows by the current logged in user in django?

My creation is a basic project about ticketing, users and assets. It's a typical application that companies have to keep a list of who has what and what issues are occurring.
So far I have (models):
**** Tickets ******************
class Ticket(models.Model):
category = models.ForeignKey('TicketCategory')
issue = models.CharField(max_length=100)
user = models.ForeignKey('Users', blank=True,null=True,related_name="tickets")
owner = models.ForeignKey(User)
**** Users *********************
class Users(models.Model):
firstname = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
email = models.CharField(max_length=100, blank=True)
business = models.ForeignKey('Business', blank=True, null=True,related_name="users")
owner = models.ForeignKey(User)
class Meta:
db_table = 'users'
verbose_name_plural = "users"
ordering = ["lastname"]
**** Assets *********************
class Assets(models.Model):
serial = models.CharField(unique=False, max_length=100)
brand = models.CharField(max_length=100)
user = models.ForeignKey('Users', blank=True, null=True, related_name="assets")
location = models.ForeignKey('AssetLocation', blank=False, null=False, related_name="assets")
owner = models.ForeignKey(User)
I have stripped them down a bit to exclude the useless info. There are others also like AssetsLocations, Categories etc., all of them in the same pattern - the owner is added in the end as a Foreign Key.
I have created some form of authentication, so every logged in user will have his own tickets, assets, and users (employees actually). Filtering is needed so the data of each user ONLY are displayed after every successful authentication.
I am using CBVs and override the get_queryset to enable filtering by the user currently logged in:
Views.py
class TicketList(ListView):
template_name = 'assets/ticket_list.html'
def get_queryset(self):
user = self.request.user
return Ticket.objects.filter(owner_id=user.id).select_related('user','asset','category')
def get_context_data(self, **kwargs):
context = super(TicketList, self).get_context_data(**kwargs)
context['totalTickets'] = self.get_queryset().count()
context['tickets'] = self.get_queryset().select_related('user','asset','category')
return context
Everything works successfully and only logged_in user's data are shown. Then I am trying to create a new Ticket:
class TicketCreate(CreateView):
fields = [ 'category', 'issue', 'user']
template_name = 'assets/ticket_form.html'
def get_queryset(self):
user = self.request.user
return Ticket.objects.filter(owner_id=user.id)
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.owner_id = self.request.user.id
self.object.save()
return HttpResponseRedirect(self.get_success_url())
success_url = reverse_lazy('ticket_list')
I am getting everything posted in the form template by using {{ form.category }}, {{ form.issue }} etc. The issue I am facing is that the drop-down boxes displayed in the form, for example the {{ form.user }} should be displaying only the users where user.owner = self.request.user.id, in simple words: the users that the owner created. Instead of it, all the users in the database are displayed.
Isn't it obvious which is the question :) ?