Запросы Django для ManyToManyFields
Я пытаюсь сделать клон приложения для знакомств и пытаюсь получить профили, которые соответствуют условиям пользователя. Я создал модель Profile, которая много-ко-многим сама с собой, и модель Match, которая объединяет 'liker' и 'likee' и добавляет дополнительные поля. Я пытаюсь получить все профили, которые я еще не пролистал. Я смог сделать это с помощью нескольких обращений к базе данных, но хочу знать, есть ли способ сделать это с помощью одного/нескольких запросов.
мои модели выглядят следующим образом
class Profile(models.Model):
class MatchGenderChoices(models.TextChoices):
FEMALE = 'FEMALE'
MALE = 'MALE'
ALL = 'ALL'
class GenderChoices(models.TextChoices):
FEMALE = 'FEMALE'
MALE = 'MALE'
NONBINARY = 'NONBINARY'
display_name = models.CharField(max_length=30, null=True)
age = models.IntegerField(null=True, blank=False)
gender = models.CharField(max_length=10, choices = GenderChoices.choices, null = True, blank = False)
user = models.OneToOneField(User, on_delete=models.CASCADE)
liked_profiles = models.ManyToManyField('self', through= 'Match')
match_distance = models.IntegerField(default = 30)
match_age_max = models.IntegerField(default = 99)
match_age_min = models.IntegerField(default = 18)
match_gender = models.CharField(max_length=10, choices = MatchGenderChoices.choices, null = True, blank = False)
city = models.CharField(max_length=30, null=True)
latitude = models.DecimalField(max_digits=10, decimal_places=6, null = True)
longitude = models.DecimalField(max_digits=10, decimal_places=6, null = True)
age = models.IntegerField(null=True, blank=False,validators=[MinValueValidator(MIN_AGE), MaxValueValidator(MAX_AGE)])
bio = models.TextField(max_length=5000, default = "Add a bio", null = True)
profile_picture_url = models.ImageField(default = os.path.join( "media", "images","default_profile_picture.jpg"), blank = True, upload_to = "images/")
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
class Match(models.Model):
liker = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name = "liker")
likee = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name = "likee", null = True)
match = models.BooleanField(default= False)
date_liked= models.DateField(auto_now=True)
date_confirmed =models.DateField(null= True, blank = True)
class Meta:
unique_together = [['liker', 'likee']]
и то, как я реализую получение этой "колоды" профилей, выглядит следующим образом
def get_profiles(profile):
# returns list of profiles where the age and genders match the user's choices
exclude_id_list = [profile.id]
exclude_id_list.extend(list(Match.objects.filter(liker_id =profile.id).values_list('likee_id', flat=True)))
exclude_id_list.extend( list(Match.objects.filter(Q(likee_id=profile.id) & ~Q(date_confirmed__isnull=True) ).values_list('liker_id', flat=True)))
if profile.match_gender == 'ALL':
matches = Profile.objects.exclude(id__in = exclude_id_list).filter(Q(age__lte=profile.match_age_max) & Q(age__gte=profile.match_age_min))
else:
matches = Profile.objects.exclude(id__in = exclude_id_list).filter(Q(age__lte=profile.match_age_max) & Q(age__gte=profile.match_age_min) & Q(gender=profile.match_gender))
Я почти уверен, что делаю что-то совершенно неправильно, но я совершенно не понимаю, с чего начать.
вот пример того, как можно работать со многими ко многим:
class A(models.Model):
name= models.CharField(...)
class B(models.Model):
a= models.ManyToManyField(A)
вы можете получить доступ к данным таким образом:
model_b_object.a.all()
или
A.objects.filter(b=model_b_object)