where puting ForeignKey in django? - python

one of the questions that came to my mind is that in a many-to-one relationship in Django, where should the foreign key be located? I mean, it should be in many or in part one?
For example, we have two classes, post and comment: in this case, where should the ForeignKey be located in the comment or post class?
post model :
class post(models.model):
created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ManyToManyField("PostCategory", blank=True)
caption = models.CharField(max_length=2000)
comment model :
class Comment(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
verbose_name=_('user'), on_delete=models.CASCADE)
text = models.TextField()
Now here is the comment field where the foreign key should be defined?

Foreign key must be used on the "Many" side of the Many-to-one relationships.
In your question, you have Post and Comment models. Since each post can have many comments, you should put a foreign key into your Comment model.
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)

Related

How to get value from the different django model in DTL?

I am having 3 different models - User, Thread and UserProfile.
User model contains information like ID, First_name and Last_name.
Thread model contains information like
class Thread(models.Model):
first_person = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='thread_first_person')
second_person = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True,related_name='thread_second_person')
updated = models.DateTimeField(auto_now=True)
and UserProfile model,
class UserProfile(models.Model):
custom_user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
picture = models.ImageField(default='profile_image/pro.png', upload_to='profile_image', blank=True)
when I am trying to get all the threads from Thread model and pass it from views.py to my HTML template then I can access User model fields like -
{{ thread.second_person.ID}} {{ thread.second_person.First_name}}
But how can I access picture field from UserProfile with the help of custom_user ?
I'm a little confused: you say you have three models User, Thread and UserProfile. But inside your UserProfile model you reference a CustomUser model as the one-to-one relationship for the custom_user field. Then in your Thread model you reference a plain User model as the FKs for the first_person and second_person fields. Do you have 3 models or 4?
Assuming you only have 3 models, and that CustomUser is actually just User, then what you're trying to achieve should be doable. However you may need to change your conventions regarding related names to best practices in order to do so cleanly.
I have set up the models I think you need roughly below, and the code needed to access the relevant parts of each model within the template layer:
#models.py
class User(AbstractBaseUser):
# User Model Code
class Thread(models.Model):
first_person = models.ForeignKey(
User,
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='thread_first_persons' # Note the Plural
)
# Related name for a FK is a one-to-many relationship
# (i.e. 1 User can be first_person on many threads)
# This may not be your desired behaviour, but it is possible on current set-up
second_person = models.ForeignKey(
User,
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='thread_second_persons'
) # As above
updated = models.DateTimeField(auto_now=True)
class UserProfile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE
related_name='user_profile'
)
# Note: custom_user is confusing nomenclature.
# The above is best practice for User <> UserProfile 1-to-1 relationships
picture = models.ImageField(
default='profile_image/pro.png',
upload_to='profile_image',
blank=True
)
Now when you want access to the UserProfile from the Thread object, you can do so as follows inside a template:
{{ thread.second_person.user_profile.picture }}
Side Note: in your views.py file, if you are sending just the thread to your template, then to save your database several queries I would optimise with the following select_related parameters:
#views.py
threads = Thread.objects.select_related(
'first_person', 'first_person__user_profile',
'second_person', 'second_person__user_profile'
).all()
thread = Thread.objects.select_related(
'first_person', 'first_person__user_profile',
'second_person', 'second_person__user_profile'
).get(id=id)

Django - Query by foreign key in views

I am trying to make a button on the post that when a user cliks on it, is requesting to be added to the post as an attendance and then, the author of the post has to approve that request.
Models.py
class Attending(models.Model):
is_approved = models.BooleanField(default=False)
attending = models.ManyToManyField(User, related_name='user_event_attending')
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField(blank=True)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
attending = models.ForeignKey(Attending, on_delete=models.CASCADE, verbose_name='atending', null=True)
My problem here is that every time I writte a query for the button is giving me erros and I couldn`t figure it out how to get the reverse of the foreign key.
This is my code on my views.py
def request_event(request, pk):
previous = request.META.get('HTTP_REFERER')
try:
query = Attending.objects.get(pk=pk)
request_attending = query.post_set.add(request.user)
messages.success(request, f'Request sent!')
return redirect(previous)
except query.DoesNotExist:
return redirect('/')
Thank you very much for your help in advance!
This: query.post_set is just relationship. You cannot call method add just like that. You can add to ManyToMany relation and I believe you want to add user to Attending.attending field, not directly to Post object. Change that to:
...
query = Attending.objects.get(pk=pk)
query.attending.add(request.user)
messages.success(request, f'Request sent!')
....
| Update |
I think you should consider rearraning your relationships. If I understand your plan, you should go this way:
class Attending(models.Model):
...
attendant = models.ForeignKey(User, related_name='events_attending', on_delete=models.CASCADE)
post = models.ForeignKey('Post', on_delete=models.CASCADE)
class Post(models.Model):
...
author = models.ForeignKey(User, on_delete=models.CASCADE)
For one Post object there can be many Attending objects, then you can use relations like that:
att = Attending.objects.first()
att.post # get related Post object from ForeignKey | there is only one
post = Post.objects.first()
post.attending_set.all() # get all related Attending objects
Post.objects.get(attending=att) # get Post object that the Attending object have in ForeignKey field
user = User.objects.first()
user.post_set.all() # get all Post objects that User is author in
user.events_attending.all() # get all related Attending objects
For more check Django Docs.

Django ForeignKey.limit_choices_to with ForeignKey to ManyToMany scenario

I have a complex relation scenario as shown below. I'd like limit_choices_to Questions that are related to JobChecklistAnswer.job_checklist.checklist on JobChecklistAnswer.question.
How can I filter those Questions as Q object (or callable as the docs say)?
class Checklist(models.Model):
name = models.CharField(_("name"), max_length=150)
description = models.CharField(_("description"), max_length=150)
class Question(models.Model):
checklist = models.ForeignKey(Checklist, on_delete=models.CASCADE)
question = models.CharField(_("question"), max_length=200)
class Job(models.Model):
...
...
class JobChecklist(models.Model):
job = models.ForeignKey(Job, on_delete=models.CASCADE)
checklist = models.ForeignKey(Checklist, on_delete=models.CASCADE)
class JobChecklistAnswer(models.Model):
job_checklist = models.ForeignKey(JobChecklist, on_delete=models.CASCADE)
# FIXME: Add limit_choices_to query question
question = models.OneToOneField(ChecklistItem, on_delete=models.CASCADE)
answer = models.TextField(_("answer"))
In contrast to the OneToOneField "reverse" relation, a ForeignKey "reverse" relation returns a QuerySet.
You are not returning a queryset here in the OneToOneField, You are only reversing a relation between them
So the first step is to change OneToOneField into a ForeignKey
then you can use limit_choices_to attribute on ForeignKey

Migrate django model primary key and cascade to related objects

I have two models as shown below. ArticlePost is related to Article by a Foreign Key. I'm wanting to remove name as a primary key on Article and instead have the Django default id field. What is the best steps to do this so that all related ArticlePosts will maintain the correct Foreign Key to Article?
class Article(models.Model):
name = models.CharField(max_length=200, primary_key=True)
class ArticlePost(models.Model):
article = models.ForeignKey(Article, null=False, db_index=True)
created_at = models.DateTimeField(auto_now_add=True)
comment = models.TextField(blank=True)

Query ManyToMany relations without a named through field

I have this setup in my models:
class Author(models.Model):
name = models.CharField(max_length=100)
class Topic(models.Model):
name = models.CharField(max_length=100)
class Article(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author, null=True, blank=True)
topics = models.ManyToManyField(Topic, null=True, blank=True)
Given an author, I want to know which topics he wrote about:
def author_info(request, pk):
author = get_object_or_404(Author, pk=pk)
topics = ????
If I had specified a through field, I could use that, but now Django makes the through field for me, and since its supposed to be transparent, Id rather not reference the field (unless there is a proper Django construction for that).
Use Lookups that span relationships:
topics = Topic.objects.filter(article__authors=author).distinct()
Note: you have to use distinct here, because the same topic can be selected by different articles.

Categories