Django запрос отношения ManyToMany из parent=ForeignKey('self')
Это для проекта блога на Django. У меня есть модель 'Profile' и 'TechStackCategory', где они имеют отношения ManyToMany. Profile - это профиль пользователя для блога. TechStackCategory имеет категории стеков пользователя, которые он знает.
Пример моделиTechStackCategory: Languages, Languages -> Python, Languages -> Java, Frameworks, Frameworks -> Django
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
background_image = models.ImageField(upload_to='profile_background_pics', blank=True, null=True,)
bio = models.CharField(max_length=200, help_text="200 characters or less")
tech_stack_cat = models.ManyToManyField('TechStackCategory', blank=True)
def __str__(self):
return f"{self.user.username}'s profile"
class TechStackCategory(models.Model):
parent = models.ForeignKey('self', related_name='children', on_delete=models.CASCADE, blank=True, null=True)
title = models.CharField(max_length=50, unique=True)
def __str__(self):
return f"{self.title}"
class Meta:
#enforcing that there can not be two categories under a parent with same slug
# __str__ method elaborated later in post. use __unicode__ in place of
unique_together = ('title', 'parent',)
verbose_name_plural = "categories"
def __str__(self):
full_path = [self.title]
k = self.parent
while k is not None:
full_path.append(k.title)
k = k.parent
return ' -> '.join(full_path[::-1])
Поэтому я следую примеру из этого поста https://dev.to/shivamrohilla/how-to-make-a-sub-and-sub-sub-categories-in-django-most-important-216p
Дело в том, что пример в посте показывает все родительские и дочерние объекты из модели Category. Он отфильтровывает запрос в представлениях как catg = Category.objects.filter(parent=None)
, который возвращает <QuerySet [<TechStackCat: Languages>, <TechStackCat: Frameworks>]>
Я хотел бы сделать то же самое, но добавить дополнительный фильтр, чтобы отфильтровать категории пользователя.
views.py
def get_context_data(self, *args, **kwargs):
user = self.request.user
catg = TechStackCategory.objects.filter(profile__user=user).all().filter(parent=None)
context ['catg'] = catg
прямо сейчас это возвращает пустоту, так что это не работает. <QuerySet []>
и TechStackCat.objects.filter(profile__user=user).all()
возвращает <QuerySet [<TechStackCat: Languages -> Python>, <TechStackCat: Languages -> Java>]>
чтобы следовать примеру из постов, мне нужно захватить родительский объект.
Или другой вариант для меня - я могу выполнить ниже, чтобы у меня не было дублирующихся родителей. (Например: Languages, Languages, Languages -> Python, Languages -> Java) Мне просто нужно показать ([Languages -> Python, Java],[Frameworks -> Django])
parent_list = []
catg = TechStackCategory.objects.filter(profile__user=user).all()
for c in catg:
if c.parent not in parent_list:
parent_list.append(c.parent)
но я думаю, что лучший способ справиться с этим - заставить TechStackCategory.objects.filter(profile__user=user).all().filter(parent=None)
работать
извините, я знаю, что это беспорядочно... Ваша помощь будет оценена по достоинству...
edit--
Итак, в моей панели администратора (модель профиля) я выбрал следующее:
Есть ли способ автоматически захватить родительский объект (Languages), просто выбрав (Languages -> Python)
edit--
Итак, я выбрал родительский объект (Languages) в панели администратора, и он отображается так, как я хочу...
но мне интересно, есть ли способ захватить родительский объект (Languages) просто при выборе (Languages -> Python)
В принципе, в том, что вы написали, нет ничего плохого, хотя формат немного не тот. Фильтр может быть одним оператором, а вызов all()
является излишним:
TechStackCategory.objects.filter(profile__user=user, parent=None)
Вы сказали, что набор запросов, который создается только из фильтра профиля, выглядит следующим образом:
и TechStackCat.objects.filter(profile__user=user).all() возвращает <QuerySet [<TechStackCat: Языки -> Python>, <TechStackCat: Языки -> Java>]>
.
Это будут два объекта, которые оба имеют Languages
в качестве родительских объектов, и оба не пройдут фильтр parent=None
. Набор запросов также не возвращает саму категорию Languages
, предположительно потому, что она не связана с пользователем. Таким образом, у вас нет объектов, удовлетворяющих обоим условиям: а) связанных с пользователем и б) являющихся конечной родительской категорией.