I have a model that hold the users reactions and I have few types of reactions - 1,2,3,4.
The user can react few times with different values and I want to keep them in the DB.
This is my model (I'm using Generic Foreign Key, not sure if it matters).
class Reaction(models.Model):
user = models.ForeignKey('auth.User', on_delete=models.SET_NULL, null=True)
date = models.DateTimeField("Reaction date", auto_now_add=True)
content_type = models.ForeignKey(ContentType, verbose_name=_('content type'),
related_name="content_type_for_%(class)s", on_delete=models.CASCADE)
object_pk = models.TextField(_('object ID'))
root_obj = GenericForeignKey(ct_field="content_type", fk_field="object_pk")
react = models.CharField('Reaction', max_length=10)
I want to get all the the root_obj (distinct if possible) that the user reacted with specific reaction (e.g. 2), but not with a reaction of type 3,4 afterwards.
Is it possible?
Thanks
R
I hope I did this correctly. See if it works:
def view(request, object_pk):
query = Reaction.objects.filter(user=request.user, object_pk=object_pk) \
.only('react', 'date', 'root_obj')
try:
react2 = query.get(react='2')
except:
react2 = None
try:
react3 = query.get(react='3')
except:
react3 = None
try:
react4 = query.get(react='4')
except:
react4 = None
# Is there a reaction = 2 and not a reaction = 3 or 4?
if react2 and not react3 or not react4:
return react2.root_obj
# Is there a reaction = 3 or 4 along with 2?
elif react2 and react3 or react4:
if react3:
if react2.date < react3.date:
return react2.root_obj
return None
elif react4:
if react2.date < react4.date::
return react2.root_obj
return None
return None
Related
I have a function in which I have to, among other things, pass to the template the ids of the users who conducted the correspondence, but I get an error in the line:
pk_list = messages.values('user_from__pk').distinct()
views.py:
def send_chat(request):
resp = {}
User = get_user_model()
if request.method == 'POST':
post =request.POST
u_from = UserModel.objects.get(id=post['user_from'])
u_to = UserModel.objects.get(id=post['user_to'])
messages = request.user.received.all()
pk_list = messages.values('user_from__pk').distinct()
correspondents = get_user_model().objects.filter(pk__in=list(pk_list))
insert = chatMessages(user_from=u_from,user_to=u_to,message=post['message'],correspondents=correspondents)
try:
insert.save()
resp['status'] = 'success'
except Exception as ex:
resp['status'] = 'failed'
resp['mesg'] = ex
else:
resp['status'] = 'failed'
return HttpResponse(json.dumps(resp), content_type="application/json")
models.py:
class chatMessages(models.Model):
user_from = models.ForeignKey(User,
on_delete=models.CASCADE,related_name="sent")
user_to = models.ForeignKey(User,
on_delete=models.CASCADE,related_name="received")
message = models.TextField()
date_created = models.DateTimeField(default=timezone.now)
correspondents = models.ForeignKey(User,
on_delete=models.CASCADE,related_name="correspondents", null=True)
def __str__(self):
return self.message
Error:
TypeError: Field 'id' expected a number but got {'user_from__pk': 1}.
how can I fix this error?
problem is here:
pk_list = messages.values('user_from__pk').distinct()
queryset.values give you a list of dictionaries. in your case [{'user_from__pk': pk1}, {'user_from__pk': pk2},... e.t.c.]
more here: https://docs.djangoproject.com/en/4.1/ref/models/querysets/#values
And you need values_list.
pk_list = messages.values_list('user_from__pk', flat=True).distinct()
To avoid joins - you can do:
pk_list = messages.values_list('user_from_pk', flat=True).distinct()
more here:
https://docs.djangoproject.com/en/4.1/ref/models/querysets/#values-list
I have the following model which has two boolean fields. Due to my logic, they won't be both true at anytime. How can I get the field which is True in a simple straight forward way?
class Vote(models.Model):
poller = models.ForeignKey(Poller, on_delete=models.CASCADE, related_name='vote')
user = models.ForeignKey(Account, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
poller_choice_one_vote = models.BooleanField(default=False)
poller_choice_two_vote = models.BooleanField(default=False)
def __str__(self):
return f'Vote by {self.user}'
This is how I'm doing it right now:
voted_for = Vote.objects.get(poller_id=poller_id, user=request.user)
is_true = voted_for.poller_choice_one_vote
is_also_true = voted_for.poller_choice_two_vote
if is_true:
voted_for = voted_for.poller_choice_one_vote
elif is_also_true:
voted_for = voted_for.poller_choice_two_vote
else:
pass
Something like this perhaps to use the meta to get the name of the field:
voted_for = Vote.objects.get(poller_id=poller_id, user=request.user)
one = voted_for.poller_choice_one_vote
two = voted_for.poller_choice_two_vote
if one:
voted_for = Vote._meta.get_field(one)
elif two:
voted_for = Vote._meta.get_field(two)
I am making a change to a record in a sqlite3 database using Django, and the save() function doesn't seem to work.
I am able to save changes using the graphical admin app however.
Here is the code to the specific model I'm trying to do the save in:
def pickup(self,item):
room_items = Item.objects.filter(roomID = self.room.id)
items = [ri.item_name for ri in room_items]
if item in items:
i = Item.objects.filter(item_name = item)
i[0].roomID = 0
i[0].playerID = self.id
i[0].save()
return f'{self.name} picked up the {item} from {self.room}'
else:
return f"{item} is not in the room. can't pick it up."
the pickup function is in a class called Player. I am updating an Item record. Any solutions?
Here is the entire models file for those who want more context:
from django.db import models
import string,random
class Room(models.Model):
### Field Columns in Room Table ###
room_name = models.CharField(max_length = 64)
description = models.CharField(max_length=500, default=f"No Room description'" )
up = models.CharField(max_length = 64, default="")
down = models.CharField(max_length = 64, default="")
left = models.CharField(max_length = 64, default="")
right = models.CharField(max_length = 64, default="")
def items(self):
items = Item.objects.filter(roomID = self.id)
return [i.item_name for i in items]
def __str__(self):
return self.room_name
class Player(models.Model):
# uuid = models.UUIDField(default=uuid.uuid4, unique=True)
HP = models.IntegerField(default=10)
name = models.CharField(max_length=64, default=f"Room {random.choice(string.ascii_letters)}")#attempting to generate a random room name using ascii_letters from string library and random.choice()
room = models.ForeignKey(Room, on_delete=models.CASCADE, null=True)
# inventory = models.ForeignKey(Inventory)
def inventory(self):
inventory = Item.objects.filter(playerID = self.room.id)
return [i.item_name for i in inventory]
def pickup(self,item):
print(self.room.id)
room_items = Item.objects.filter(roomID = self.room.id)
items = [ri.item_name for ri in room_items]
if item in items:
i = Item.objects.filter(item_name = item)
i[0].roomID = 0
i[0].playerID = self.id
i[0].save()
i[0].persist()
return f'{self.name} picked up the {item} from {self.room}'
else:
return f"{item} is not in the room. can't pick it up."
def drop_item(self,item):
pass
def initialize(self,start):
# start = input(f"{self.name}, you are outside the PyTower. It is a 10 story tower. There is a treasure chest on the top floor. Do you have what it takes to reach the top??? type 'y' to enter Pytower: ")
if start == 'y':
self.room = Room.objects.get(room_name = "Foyer")
print(f"{self.name}, you have now entered the {self.room.room_name}")
return f"{self.name}, you have now entered the {self.room.room_name}"
else:
print(f"{self.name}, when you're ready for Pytower, you may enter!")
return f"{self.name}, when you're ready for Pytower, you may enter!"
print(self.room.description)
print('in room: ', self.room, 'up:',self.room.up, 'down:',self.room.down, 'left:',self.room.left, 'right:', self.room.right)
return self.room
def move(self,way=""):
# print(self.room[way]) #causes error, Room object not subscriptable
# print(way)
# if self.room[way]:
# pass
if way == 'up':
if not self.room.up:
print('you cannot go that way. no rooms there...')
return 'you cannot go that way. no rooms there...'
else:
self.room = Room.objects.get(room_name = self.room.up)
print('in room: ', self.room, 'up:',self.room.up, 'down:',self.room.down, 'left:',self.room.left, 'right:', self.room.right)
return self.room
elif way == 'down':
if not self.room.down:
print('you cannot go that way. no rooms there...')
return 'you cannot go that way. no rooms there...'
else:
self.room = Room.objects.get(room_name = self.room.down)
print('in room: ', self.room, 'up:',self.room.up, 'down:',self.room.down, 'left:',self.room.left, 'right:', self.room.right)
return self.room
elif way == 'left':
if not self.room.left:
print('you cannot go that way. no rooms there...')
return 'you cannot go that way. no rooms there...'
else:
self.room = Room.objects.get(room_name = self.room.left)
print('in room-', self.room, 'up-',self.room.up, 'down-',self.room.down, 'left-',self.room.left, 'right-', self.room.right)
return self.room
elif way == 'right':
if not self.room.right:
print('you cannot go that way. no rooms there...')
return 'you cannot go that way. no rooms there...'
else:
self.room = Room.objects.get(room_name = self.room.right)
print('in room: ', self.room, 'up:',self.room.up, 'down:',self.room.down, 'left:',self.room.left, 'right:', self.room.right)
return self.room
else:
print('you have entered an invalid direction')
return 'you have entered an invalid direction'
def __str__(self):
if not self.room:
return f"{self.name} is outside."
else:
return f"{self.name} in {self.room}"
class Item(models.Model):
item_name = models.CharField(max_length=64)
strength = models.IntegerField(default=5)
item_type = models.CharField(max_length=64,default="weapon")
# playerID = models.ForeignKey(Player, on_delete=models.CASCADE, null=True)
# roomID = models.ForeignKey(Room, on_delete=models.CASCADE, null=True)
playerID = models.IntegerField(blank=True,null=True)
roomID = models.IntegerField(default=1,null=True,blank=True)
def persist(self):
self.save()
def __str__(self):
return self.item_name
To understand why your model isn't saving, you must first understand how querysets are evaluated. Essentially, anytime you iterate over them, or slice them, they will hit the database, however there are caveats to this.
Consider the following abstract example:
def MyModel(models.Model):
column = models.IntegerField()
>>> MyModel.objects.create(column=1)
<MyModel: MyModel object (1)>
>>> queryset = MyModel.objects.all()
Slicing:
>>> queryset[0].column = 2
>>> queryset[0].save()
>>> queryset[0].column
1
In the example above, I took a slice, eg. queryset[0], which hits the database, then immediately took a second slice, to try and save the changes made, which hits the database a second time. Finally, I took a third slice, which hits the database again.
Since the first slice is not the same object as the object I called .save() on, the changes are not reflected in the database. To fix this, simply save a reference to the slice as a variable:
>>> instance = queryset[0]
>>> instance.column = 2
>>> instance.save()
>>> instance.column
2
In this example, I only hit the database twice: once when I call instance = queryset[0], and a second time in instance.save().
Here is the optimized version of your code:
def pickup(self, item_name):
items = Item.objects.filter(item_name=item_name, roomID=self.room.id)
if items:
item = items[0]
item.roomID = 0
item.playerID = self.id
item.save()
return 'message'
return 'no item'
This is my Model class
class SubJobs(models.Model):
id = models.AutoField(primary_key = True)
subjob_name = models.CharField(max_length=32,help_text="Enter subjob name")
subjobtype = models.ForeignKey(SubjobType)
jobstatus = models.ForeignKey(JobStatus, default= None, null=True)
rerun = models.ForeignKey(ReRun,help_text="Rerun")
transfer_method = models.ForeignKey(TransferMethod,help_text="Select transfer method")
priority = models.ForeignKey(Priority,help_text="Select priority")
suitefiles = models.ForeignKey(SuiteFiles,help_text="Suite file",default=None,null=True)
topofiles = models.ForeignKey(TopoFiles,help_text="Topo file",default=None,null=True)
load_image = models.NullBooleanField(default = True,help_text="Load image")
description = models.TextField(help_text="Enter description",null=True) command = models.TextField(help_text="Command",null=True)
run_id = models.IntegerField(help_text="run_id",null=True)
pid_of_run = models.IntegerField(help_text="pid_of_run",null=True)
hold_time = models.IntegerField()
created = models.DateTimeField(default=timezone.now,null=True)
updated = models.DateTimeField(default=timezone.now,null=True)
finished = models.DateTimeField(null=True)
The user might want to update a entry and may choose to update only few fields among these. How do I write a generic update statement that would update only the fields that were passed?
I tried this.
def update_subjob(request):
if (request.method == 'POST'):
subjobs_subjobid = request.POST[('subjob_id')]
post_data = request.POST
if 'subjob_name' in post_data:
subjobs_subjobname = request.POST[('subjob_name')]
if 'subjob_type' in post_data:
subjobs_subjobtype = request.POST[('subjob_type')]
if 'rerun_id' in post_data:
subjobs_rerun_id = request.POST[('rerun_id')]
if 'priority_id' in post_data:
subjobs_priority_id = request.POST[('priority_id')]
if 'transfer_method' in post_data:
subjobs_transfermethod = request.POST[('transfer_method')]
if 'suitefile' in post_data:
subjob_suitefile = request.POST[('suitefile')]
if 'topofile' in post_data:
subjob_topofile = request.POST[('topofile')]
try:
subjobinstance = SubJobs.objects.filter(id=subjobs_subjobid).update(subjob_name=subjobs_subjobname,
updated=datetime.now())
except Exception as e:
print("PROBLEM UPDAING SubJob!!!!")
print(e.message)
How do I write a generic update to update only those fields which are sent in request.POST?
You'd better use Forms. But if you insist on your code it could be done like this.
Suppose you have variable field_to_update where every field that you are waiting in request is listed.
subjobs_subjobid = request.POST[('subjob_id')]
field_to_update = ('subjob_name','subjob_type', 'rerun_id', 'priority_id', 'transfer_method', 'suitefile', 'topofile')
post_data = request.POST
to_be_updated = {field: post_data.get(field) for field in field_to_update if field in post_data}
# then you need to get the object, not filter it
try:
subjobinstance = SubJobs.objects.get(id=subjobs_subjobid)
subjobinstance.update(**to_be_updated, updated=datetime.now())
except ObjectDoesNotExist: # from django.core.exceptions
print('There is no such object') # better to use logger
except Exception as e:
print("PROBLEM UPDAING SubJob!!!!")
print(e.message)
if "allotted_pto" (paid time off) is an integer field (expressing number of days) in a UserProfile model:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
fullname = models.CharField(max_length=64, unique=False)
company = models.CharField(max_length=50, choices=CLIENT_CHOICES)
...
allotted_pto = models.IntegerField(max_length=2, blank=True, null=True)
...
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
and "total_days" returns an integer from a vacation request model:
class LeaveRequest(models.Model):
employee = models.ForeignKey(UserProfile)
supervisor = models.ForeignKey(UserProfile, related_name='+', blank=False, null=False)
...
total_days = models.IntegerField(max_length=2, blank=True, null=True)
def __unicode__ (self):
return u'%s %s' % (self.employee, self.submit_date)
def save(self, *args, **kwargs):
fromdate = self.start_date
todate = self.return_date
daygenerator = (fromdate + timedelta(x + 1) for x in xrange((todate - fromdate).days))
self.total_days = sum(1 for day in daygenerator if day.weekday() < 5)
super(LeaveRequest, self).save(*args, **kwargs)
...
how can I construct a view that gives me the sum of "total_days" from a filter set of records and subtract that sum from the "allotted_pto" in the user profile? The simple view I wrote (see below) produces the number of "total_days" objects (in dictionary form) as opposed to counting the actual days, and the request for "allotted_pto" is apparently incorrectly constructed because it returns nothing at all...
#views.py
def leave_screen(request, id):
profile = UserProfile.objects.get(user=id)
records = LeaveRequest.objects.filter(employee=id)
agg_pto = LeaveRequest.objects.aggregate(Count('total_days'))
if profile.allotted_pto: #if the allotted_pto field in UserProfile is not empty
allotted_pto = profile.allotted_pto
remaining_pto = allotted_pto - agg_pto
else:
remaining_pto = "na"
return render_to_response("vacation/leave_request.html", {'records': records, 'agg_pto': agg_pto, 'remaining_pto': remaining_pto})
ok, figured out calculation:
def leave_screen(request, id):
...
agg_pto = LeaveRequest.objects.filter(employee=id).aggregate(Sum('total_days'))
agg_pto = agg_pto['total_days__sum']
just have to figure out how to pull the allotted_pto integer from the User Profile model.
ok, so this wasn't as difficult as I thought. The first challenge was to get an aggregate sum of objects. My first attempt was close but I should have just used "Sum" as opposed to "Count":
agg_pto = LeaveRequest.objects.filter(employee=id).aggregate(Sum('total_days'))
then I just used the python method for extracting the value from a dictionary:
agg_pto = agg_pto['total_days__sum']
finally:
def leave_screen(request, id):
user = request.user.id
profile = request.user.get_profile()
records = LeaveRequest.objects.filter(employee=id).order_by('-submit_date')
agg_pto = LeaveRequest.objects.filter(employee=id).aggregate(Sum('total_days'))
agg_pto = agg_pto['total_days__sum']
allotted_pto = profile.allotted_pto
if allotted_pto: #if the allotted_pto field in UserProfile is not empty
remaining_pto = allotted_pto - agg_pto
else:
remaining_pto = "na"
supervised_records = LeaveRequest.objects.filter(supervisor=id).order_by('-submit_date')
return render_to_response("vacation/leave_request.html", {'records': records, 'supervised_records': supervised_records, 'agg_pto': agg_pto, 'allotted_pto': allotted_pto, 'remaining_pto': remaining_pto, 'profile': profile })
I don't know why it was so hard for me to figure out the syntax for pulling objects from the UserProfile. But I do know that the django-debug-toolbar is very helpful.