IntegrityError :(1062, "Duplicate for key 'user_id'") - python

I am trying to do some job portal kind of thing. I want to that one user can apply to different jobs but not the same one.Here when one user applied to one job he cant apply for another. That's the problem and by using my logic when i running the view i got
'integrityerror'
. Please help me.
Thank You
model.py
class JobsApplied(models.Model):
'''
Events
'''
class Meta:
'''
Meta properties for this model
'''
app_label = 'admin'
verbose_name_plural = 'JobsApplied'
job = models.ForeignKey('Job', db_index=True,related_name='appliedjobs')
user = models.OneToOneField(UserProfile)
create_date = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
'''
Returns object display name
'''
return self.job
views.py
def job_applyview(request):
job_id = request.POST.get('job_id')
## if admin have rights to apply the job please remove "not request.user.is_staff"
# job_id = 11
if request.user and not request.user.is_staff:
job = Job.objects.get(id=job_id)
### please enable below commands after verify
user = UserProfile.objects.get(user__id=request.user.id)
# applied_job = JobsApplied.objects.get(job=job, user=user)
applied_job = JobsApplied.objects.create(job=job, user=user)
applied_job.save(force_insert=True)
message = "you have applied in as " + str(job.job_title)
job_title = Job.objects.get(id=job_id).job_title
industry_id = Job.objects.get(id=job_id)
emp_name = IndustryProfile.objects.get(id=industry_id.industry_id).name
email = IndustryProfile.objects.get(id=industry_id.industry_id).email
b = StudentProfile.objects.get(user_profile=UserProfile.objects.get(user_id=request.user.id))
name = b.name
contact_num = b.mobile_phone
location = b.address_line1
if b.resume:
resume = b.resume.url
else:
resume = ""
body = '''Dear %s, \n The following candidate applied for the job that you have published in Nasscom Jobs Portal.
\n \n Job Title : %s \n name : %s \n Contact_No : %s \n Address : %s \n Resume : %s\n \n Thanks,\n \n Job Portal Support Team''' % (
emp_name, job_title, name, contact_num, location, resume)
email = EmailMessage('Job Applied', body, to=[email])
email.send()
form = JobForm(instance=job)
return render_to_response(
'admin/job.html', {'form': form, 'message': message},
context_instance=RequestContext(request),
)
else:
return redirect('/admin/')

You said:
one user can apply to different jobs
but you implemented as:
class JobsApplied(models.Model):
# [...]
user = models.OneToOneField(UserProfile)
OneToOne field is used when 2 objects are strongly linked together. Here, you say that any instance of JobApplied correspond to a unique user (which seems correct) but you also said any User is linked to 1 (and only 1) JobApplied instance. So in that form, a user cannot apply to 2 or more jobs.
What you want here is a 0..n relationship: you want a user apply to 0 or more Jobs. So you have to declare a ForeignKey in your UserProfile model.

Related

django left join with where clause subexpression

I'm currently trying to find a way to do something with Django's (v1.10) ORM that I feel should be possible but I'm struggling to understand how to apply the documented methods to solve my problem.
Edit: So here's the sql that I've hacked together to return the data that I'd like from the dbshell, with a postgresql database now, after I realised that my original sqlite3 backed sql query was incorrect:
select
voting_bill.*,vv.vote
from
voting_bill
left join
(select
voting_votes.vote,voting_votes.bill_id
from
voting_bill
left join
voting_votes
on
voting_bill.id=voting_votes.bill_id
where
voting_votes.voter_id = (select id from auth_user where username='richard' or username is Null)
)
as
vv
on
voting_bill.id=vv.bill_id;
Here's the 'models.py' for my voting app:
from django.db import models
from django.contrib.auth.models import User
class Bill(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
result = models.BooleanField()
status = models.BooleanField(default=False)
def __str__(self):
return self.name
class Votes(models.Model):
vote = models.NullBooleanField()
bill = models.ForeignKey(Bill, related_name='bill',
on_delete=models.CASCADE,)
voter = models.ForeignKey(User, on_delete=models.CASCADE,)
def __str__(self):
return '{0} {1}'.format(self.bill, self.voter)
I can see that my sql works as I expect with the vote tacked onto the end, or a null if the user hasn't voted yet.
I was working to have the queryset in this format so that I can iterate over it in the template to produce a table and if the result is null I can instead provide a link which takes the user to another view.
I've read about select_related and prefetch_related, but as I said, I'm struggling to work out how I translate this to how I can do this in SQL.
Hope I correctly understood your problem. Try this:
votes = Votes.objects.filter(voter__username='django').select_related('bill')
You can use this. But I think you do not need select_related in this case.
bills_for_user = Bill.objects.filter(votes__voter__username='django').select_related('votes').distinct()
Now you can iterate your bills_for_user
for bill in bills_for_user:
bill_name = bill.name
bill_description = bill.description
bill_result = bill.result
bill_status = bill.status
# and there are several variants what you can with votes
bill_votes = bill.votes_set.all() # will return you all votes for this bill
bill_first_vote1 = bill.votes_set.first() # will return first element in this query or None if its empty
bill_first_vote2 = bill.votes_set.all()[0] # will return first element in this query or Error if its empty
bill_last_vote = bill.votes_set.last()[0] # will return last element in this query or None if its empty
# you can also filter it for example by voting
bill_positive_votes = bill.votes_set.filter(vote=True) # will return you all votes for this bill with 'vote' = True
bill_negative_votes = bill.votes_set.filter(vote=False) # will return you all votes for this bill with 'vote' = False
bill_neutral_votes = bill.votes_set.filter(vote=None) # will return you all votes for this bill with 'vote' = None

django doesn't save manytomany object

I have this models
class Base(models.Model):
city = models.CharField(max_length=100)
district = models.CharField(max_length=100)
Owner = models.ForeignKey(User, related_name='%(class)s__Game_Owner')
attending = models.ManyToManyField(User)
requested = models.ManyToManyField(User, related_name="%(class)s__requested")
invited = models.ManyToManyField(User, related_name="%(class)s__invited")
teams = models.ManyToManyField(Team)
field = models.CharField(max_length=100)
Hash = models.CharField(max_length=32, blank=True)
and I have other two classes inherting from this base. The class names are
reservation and enlisting
I created this function in the views
def test_join_event(event_id, event_type, user_id):
event = None
if event_type =='enlisting':
event = enlistings.objects.get(id=event_id)
elif event_type =='reservation':
event = reservations.objects.get(id=event_id)
requested_user = User.objects.get(id=user_id)
if requested_user == event.Owner:
return "Error: you are already part of the event"
if requested_user in event.players.all():
return "Error 2!"
if requested_user in event.invited.all():
return "You are already invited to the event!"
if requested_user in event.requested.all():
return "You can't send your request again!"
event.requested.add(requested_user)
event.save()
return "Saved!!"
when I call the function from the interpreter it keeps giving me "Saved" however it should add the user to the requested list and the next time I call the function it returns "You can't send your request again" !!!
I tried the function from the browser it returns saved too, but when I look at the object in the interpreter I see that the requsted list is empty (doesn't have the player I just added)
When I checekd from the interpreter I got the same problem!! I only noticed that I only can add the user who owns that event.
for example like this code
event.requested.add(event.owner)
event.requested.all() # The user is added successfully !!
I can't understand why this is happening. Any ideas??

Display relevant records from many to many in django-tables2

OK, so I have an Item class that has a many-to-many attribute to User through a 'Roles' class. I am trying to create a django-table for the Items such that out of any of the roles attached to the item, if the current User is attached to that role, the name of the role displays. I hope that makes some sort of sense. Here's what I have so far, which I didn't really expect to work because I don't see how the Table class can know about the request/user. I'm stuck.
models.py
class Item(models.Model):
name = models.CharField(max_length=255)
owner = models.ForeignKey(User, related_name='Owner')
roles = models.ManyToManyField(User, through='Role')
class Role(models.Model):
role_type = models.ForeignKey(RoleType)
user = models.ForeignKey(User)
item = models.ForeignKey(Item)
tables.py
class OwnedTable(tables.Table):
roles = tables.Column()
user = request.user
def render_roles(self):
for role in roles:
if role.User == user:
return role.role_type
else:
pass
class Meta:
model = Item
attrs = {"class": "paleblue"}
fields = ('id', 'name', 'owner', 'roles')
You can get the request object from self.context. So if you only need request.user, that's one way to do it.
class OwnedTable(tables.Table):
roles = tables.Column(empty_values=())
def render_roles(self):
user = self.context["request"].user
...
Otherwise, #mariodev's solution works.
It seems like there's no way of using auth user without some overriding.
You can override __init__ for our table class like this:
class OwnedTable(tables.Table):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super(OwnedTable, self).__init__(*args, **kwargs)
then, inside view, you call table with user argument, like so
table = OwnedTable(Person.objects.all(), user=request.user)
now you can use self.user inside render_roles method to refer to the currently logged in user.
Another solution is shown on https://github.com/bradleyayers/django-tables2/issues/156, which worked for me after some adjustments for my setup.
Given that a Person would have an M2M to Contacts, and you want to display all contacts for that Person in django-tables2, then the following would do:
class PersonTable(tables.Table):
person_contacts = tables.Column(accessor="contacts", verbose_name="Contacts")
def render_person_contacts(self, value, table):
clist = ""
cfirst = True
conts = list(value.all())
for c in conts:
if not cfirst:
clist += "<br />"
else:
cfirst = False
print c.id
uri = reverse('cont_detail', kwargs={'pk': c.id})
clist += '' + c.name + '' + ' (' + c.relation + ')'
return mark_safe(clist)
You basically add a column with a non-existent name, set the accessor to the M2M field name, then call render_<newly_added_column> where you obtain what you need from value.

Django-powered library checkout system

I am working on a library system to manage certain items in our office, I don't need a full-blown integrated library system so I decided to hand roll one with Django.
Below is a simplified version of my model:
class ItemObjects(models.Model):
# Static Variables
IN_STATUS = 'Available'
OUT_STATUS = 'Checked out'
MISSING = 'Missing'
STATUS_CHOICES = (
(IN_STATUS, 'Available'),
(OUT_STATUS, 'Checked out'),
(MISSING, 'Missing'),
)
# Fields
slug = models.SlugField(unique=True)
date_added = models.DateField(auto_now_add=True)
last_checkin = models.DateTimeField(editable=False, null=True)
last_checkout = models.DateTimeField(editable=False, null=True)
last_activity = models.DateTimeField(editable=False, null=True)
status = models.CharField(choices=STATUS_CHOICES, default=IN_STATUS, max_length=25)
who_has = models.OneToOneField(User, blank=True, null=True)
times_out = models.PositiveIntegerField(default=0, editable=False)
notes = models.CharField(blank=True, max_length=500)
history = models.TextField(blank=True, editable=False)
pending_checkin = models.BooleanField(default=False)
pending_transfer = models.BooleanField(default=False)
At first I was using a method on ItemObject to process checking out an item to a user and who_has was an EmailField because I couldn't get a CharfField to populate with the logged in user's name, but I figured using a OneToOneField is probably closer to the "right" way to do this.. While who_has was an EmailField, the following method worked:
def check_out_itemobject(self, user):
user_profile = user.get_profile()
if self.status == 'Available' and self.who_has == '':
self.status = 'Checked out'
self.who_has = user.email
self.last_checkout = datetime.datetime.now()
self.last_activity = datetime.datetime.now()
self.times_out += 1
if self.history == '':
self.history += "%s" % user_profile.full_name
else:
self.history += ", %s" % user_profile.full_name
if user_profile.history == '':
user_profile.history += self.title
else:
user_profile.history += ", %s" % self.title
else:
return False # Not sure is this is "right"
user_profile.save()
super(ItemObjects, self).save()
Now that I am using a OneToOneField this doesn't work, so I started looking at using a subclass of ModelForm but none of the cases I saw here on SO seemed to apply for what I am trying to do; my form would be a button, and that's it. Here are some of the questions I looked at:
Django: saving multiple modelforms simultaneously (complex case)
(Django) (Foreign Key Issues) model.person_id May not be NULL
django update modelform
So was I on the right track with a sort of altered save() method, or would a ModelForm subclass be the way to go?
EDIT/UPDATE: Many thanks to #ChrisPratt!
So I am trying to get Chris Pratt's suggestion for showing ItemHistory to work, but when I try to render it on a page I get an AttributeError that states "'User' object has no attribute 'timestamp'". So my question is, why is it complaining about a User object when last_activity is an attribute on the ItemObject object ?
My view:
#login_required
def item_detail(request, slug):
item = get_object_or_404(Item, slug=slug)
i_history = item.last_activity
user = request.user
return render_to_response('items/item_detail.html',
{ 'item' : item,
'i_history': i_history,
'user' : user })
I do not see why a User object is coming up at this point.
EDIT2: Nevermind, history is clearly a M2M field whose target is User. That's why!
Assuming users will log in and check out books to themselves, then what you most likely want is a ForeignKey to User. A book will only have one User at any given time, but presumably Users could check out other items as well. If there is some limit, even if the limit is actually one per user, it would be better to validate this in the model's clean method. Something like:
def clean(self):
if self.who_has and self.who_has.itemobject_set.count() >= LIMIT:
raise ValidationError('You have already checked out your maximum amount of items.')
Now, you checkout method has a number of issues. First, status should be a defined set of choices, not just random strings.
class ItemObject(models.Model):
AVAILABLE = 1
CHECKED_OUT = 2
STATUS_CHOICES = (
(AVAILABLE, 'Available'),
(CHECKED_OUT, 'Checked Out'),
)
...
status = models.PositiveIntegerField(choices=STATUS_CHOICES, default=AVAILABLE)
Then, you can run your checks like:
if self.status == self.STATUS_AVAILABLE:
self.status = self.STATUS_CHECKED_OUT
You could use strings and a CharField instead if you like, as well. The key is to decouple the static text from your code, which allows much greater flexibility in your app going forward.
Next, history needs to be a ManyToManyField. Right now, your "history" is only who last checked the item out or what the last item the user checked out was, and as a result is pretty useless.
class ItemObject(models.Model):
...
history = models.ManyToManyField(User, through='ItemHistory', related_name='item_history', blank=True)
class ItemHistory(models.Model):
CHECKED_OUT = 1
RETURNED = 2
ACTIVITY_CHOICES = (
(CHECKED_OUT, 'Checked Out'),
(RETURNED, 'Returned'),
)
item = models.ForeignKey(ItemObject)
user = models.ForeignKey(User)
activity = models.PostiveIntegerField(choices=ACTIVITY_CHOICES)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-timestamp'] # latest first
Which then allows you to get full histories:
some_item.history.all()
some_user.item_history.all()
To add a new history, you would do:
ItemHistory.objects.create(item=some_item, user=some_user, activity=ItemHistory.CHECKED_OUT)
The auto_now_add attribute ensures that the timestamp is automatically set when the relationship is created.
You could then actually get rid of the last_checkout and last_activity fields entirely and use something like the following:
class ItemObject(models.Model):
...
def _last_checkout(self):
try:
return self.history.filter(activity=ItemHistory.CHECKED_OUT)[0].timestamp
except IndexError:
return None
last_checkout = property(_last_checkout)
def _last_activity(self):
try:
return self.history.all()[0].timestamp
except IndexError:
return None
last_activity = property(_last_activity)
And, you can then use them as normal:
some_item.last_checkout
Finally, your checkout method is not an override of save so it's not appropriate to call super(ItemObject, self).save(). Just use self.save() instead.

How Can I Populate Default Form Data with a ManyToMany Field?

Ok, I've been crawling google and Django documentation for over 2 hours now (as well as the IRC channel on freenode), and haven't been able to figure this one out.
Basically, I have a model called Room, which is displayed below:
class Room(models.Model):
"""
A `Partyline` room. Rooms on the `Partyline`s are like mini-chatrooms. Each
room has a variable amount of `Caller`s, and usually a moderator of some
sort. Each `Partyline` has many rooms, and it is common for `Caller`s to
join multiple rooms over the duration of their call.
"""
LIVE = 0
PRIVATE = 1
ONE_ON_ONE = 2
UNCENSORED = 3
BULLETIN_BOARD = 4
CHILL = 5
PHONE_BOOTH = 6
TYPE_CHOICES = (
('LR', 'Live Room'),
('PR', 'Private Room'),
('UR', 'Uncensored Room'),
)
type = models.CharField('Room Type', max_length=2, choices=TYPE_CHOICES)
number = models.IntegerField('Room Number')
partyline = models.ForeignKey(Partyline)
owner = models.ForeignKey(User, blank=True, null=True)
bans = models.ManyToManyField(Caller, blank=True, null=True)
def __unicode__(self):
return "%s - %s %d" % (self.partyline.name, self.type, self.number)
I've also got a forms.py which has the following ModelForm to represent my Room model:
from django.forms import ModelForm
from partyline_portal.rooms.models import Room
class RoomForm(ModelForm):
class Meta:
model = Room
I'm creating a view which allows administrators to edit a given Room object. Here's my view (so far):
def edit_room(request, id=None):
"""
Edit various attributes of a specific `Room`. Room owners do not have
access to this page. They cannot edit the attributes of the `Room`(s) that
they control.
"""
room = get_object_or_404(Room, id=id)
if not room.is_owner(request.user):
return HttpResponseForbidden('Forbidden.')
if is_user_type(request.user, ['admin']):
form_type = RoomForm
elif is_user_type(request.user, ['lm']):
form_type = LineManagerEditRoomForm
elif is_user_type(request.user, ['lo']):
form_type = LineOwnerEditRoomForm
if request.method == 'POST':
form = form_type(request.POST, instance=room)
if form.is_valid():
if 'owner' in form.cleaned_data:
room.owner = form.cleaned_data['owner']
room.save()
else:
defaults = {'type': room.type, 'number': room.number, 'partyline': room.partyline.id}
if room.owner:
defaults['owner'] = room.owner.id
if room.bans:
defaults['bans'] = room.bans.all() ### this does not work properly!
form = form_type(defaults, instance=room)
variables = RequestContext(request, {'form': form, 'room': room})
return render_to_response('portal/rooms/edit.html', variables)
Now, this view works fine when I view the page. It shows all of the form attributes, and all of the default values are filled in (when users do a GET)... EXCEPT for the default values for the ManyToMany field 'bans'.
Basically, if an admins clicks on a Room object to edit, the page they go to will show all of the Rooms default values except for the 'bans'. No matter what I do, I can't find a way to get Django to display the currently 'banned users' for the Room object. Here is the line of code that needs to be changed (from the view):
defaults = {'type': room.type, 'number': room.number, 'partyline': room.partyline.id}
if room.owner:
defaults['owner'] = room.owner.id
if room.bans:
defaults['bans'] = room.bans.all() ### this does not work properly!
There must be some other syntax I have to use to specify the default value for the 'bans' field. I've really been pulling my hair out on this one, and would definitely appreciate some help.
Thanks!
UPDATE
lazerscience actually helped me find the solution in one of his comments. Basically, the way it works is if you pass a list of primary keys. To make it work I had to change:
if room.bans:
defaults['bans'] = room.bans.all() ### this does not work properly!
to
if room.bans:
defaults['bans'] = [b.pk for b in room.bans.all()]
And bam, it instantly started working (when I view the page, it will show a selectable list of Callers, with the already banned callers already highlighted (selected).
You probably need to use "initial": Django set default form values

Categories