Issue
I'm trying to create Secret Santa web site using Python Django. Issue I have is when there's odd number of participants. I'm using Django's built in User model and pairing its instances as matches for the game. In case of odd number, there will be a participant without match. Is there any way to store None in case of empty instance without raising ValueError?
Here's my code:
models.py
class Participants (models.Model):
giver = models.OneToOneField(User, on_delete=models.CASCADE, null = True, blank = True, related_name = "giver")
receiver = models.OneToOneField(User, on_delete=models.CASCADE, null = True, blank = True, related_name = "receiver")
def __str__(self):
return self.receiver.username
views.py
def matchPairs(request):
participants = User.objects.all().exclude(is_superuser=True)
participants_names = [p.id for p in participants]
i = 0
Givers = []
Receivers = []
if request.method == "POST":
[givers, receivers] = pairs_generator.generate_match(participants_names)
while i < len(receivers):
if givers[i] == None:
Givers.append(None)
else:
Givers.append(User.objects.filter(pk = givers[i]))
Receivers.append(User.objects.filter(pk = receivers[i]))
Participants.objects.create(giver = Givers[i], receiver = Receivers[i])
messages.success(request, "Matching successful! Here's the list.")
return redirect('participants')
else:
messages.error(request, "Woops. Something went wrong. Please try again.")
return redirect('participants')
generate_match.py
def generate_match(participants_names):
givers = []
receivers = []
flag = None
random.shuffle(participants_names)
i = 0
while i < len(participants_names):
if (is_even(participants_names)):
print(f'{participants_names[i]} exchanges gifts with {participants_names[i + 1]}. ')
givers.append(participants_names[i])
receivers.append(participants_names[i+1])
i += 2
else:
print(f'{participants_names[i]} has no one to buy a gift to this year. :(')
givers.append(flag)
receivers.append(participants_names[i])
participants_names.pop(i)
return givers, receivers
Any help or suggestion would be helpful.
EDIT Here's error traceback:
Traceback (most recent call last):
File "/Users/fatimavelic/Documents/Doing/projects/penv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/Users/fatimavelic/Documents/Doing/projects/penv/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/fatimavelic/Documents/Doing/projects/penv/santa/secretsanta/views.py", line 44, in matchPairs
Participants.objects.create(giver = Givers[i], receiver = Receivers[i])
File "/Users/fatimavelic/Documents/Doing/projects/penv/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/fatimavelic/Documents/Doing/projects/penv/lib/python3.9/site-packages/django/db/models/query.py", line 455, in create
obj = self.model(**kwargs)
File "/Users/fatimavelic/Documents/Doing/projects/penv/lib/python3.9/site-packages/django/db/models/base.py", line 489, in __init__
_setattr(self, field.name, rel_obj)
File "/Users/fatimavelic/Documents/Doing/projects/penv/lib/python3.9/site-packages/django/db/models/fields/related_descriptors.py", line 310, in __set__
super().__set__(instance, value)
File "/Users/fatimavelic/Documents/Doing/projects/penv/lib/python3.9/site-packages/django/db/models/fields/related_descriptors.py", line 215, in __set__
raise ValueError(
Exception Type: ValueError at /secretsanta/match-pairs/
Exception Value: Cannot assign "<QuerySet [<User: Daisy>]>": "Participants.receiver" must be a "User" instance.
Solution
Queryset.filter
returns a new Queryset oject. You want to use Queryset.get(pk=...)
instead, or Queryset.filter(...).first()
You could also avoid extra db calls completely, for example by indexing all users by their primary key: id_to_user = {_.pk: _ for _ in participants}
Answered By - Nielk
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.