I have a simple ManyToOne relationship where users can post comments to a poller object.
Comments Model
class Comments(models.Model):
poller = models.ForeignKey(Pollers, on_delete=models.CASCADE, related_name='comments')
created_on = models.DateTimeField(auto_now_add=True)
comment = models.CharField(max_length=250)
created_by = models.CharField(max_length=80)
class Meta:
ordering = ['created_on']
def __str__(self):
return 'Comment {} by {}'.format(self.body, self.name)
The View
def single_poller(request, poller_id):
"""retrieves the item clicked by the user from DB and renders
the single_poller template for further user interaction
"""
# Retrieve the item via get
poller = Pollers.objects.get(poller_id=poller_id)
# Increase the view field of the object by
poller.poller_views += 1
# Save the changed instance and overwrite new view integer
poller.save()
# Get the form for comments
form = CommentsForm
context = {
'poller': poller,
'form': form
}
return render(request, 'pollboard/single_poller.html', context)
Now I want to render the comments for each poller into my template like so
<div id="comments-choice-one-wrapper" class="comments-wrapper">
{{ poller.comments.comment }}
</div>
Somehow it doesn't render the comment I created beforehand. I checked in Django admin if the comment is rly related to the poller and this looks just fine.
poller.comments.all is a QuerySet of Comments, so this is a collection, therefore it makes no sense to use .comment since that is an attribute of a Comment object, not an attribute of QuerySet with comments.
You can enumerate over the comments.all, and thus render these comments individually:
<div id="comments-choice-one-wrapper" class="comments-wrapper">
{% for comment in poller.comments.all %}
{{ comment.comment }}
{% endfor %}
</div>
In you Comments model, using self.name or self.body makes not much sense, since that model has no name property or field. You likely should use the __str__ on the Poller:
class Comments(models.Model):
# ⋮
def __str__(self):
return f'Comment {self.comment} by {self.poller}'
Note: normally a Django model is given a singular name, so Comment instead of Comments.
Related
Hello friends I am trying to figure out how to work properly with a One to Many relationship.
I want to create two models,
The first model is Post
And a second model is Comment
Now I say that every post has many comments, and every comment has one post.
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=50)
message = models.TextField(max_length=256,null=True)
def __str__(self):
return str(self.title)
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
message = models.TextField(max_length=256, null=True)
I'm trying to figure out how I can get all the posts and all the comments so that all the comments match the post to which they belong
That is, in the functions in the views file how do I send back this option.
because on the HTML page I want to display the post with all its comments
but there are a number of posts, so how do I do that?
The only thought I can do is this:
dict = {}
all_posts = Post.objects.all()
for post in all_posts:
dict[post] = Comment.objects.filter(post=post).values()
print(dict)
but I have a feeling there is something better
You can access all related comments for a post by using post.comment_set.all() see Following relationships “backward”
{% for post in all_posts %}
{{ post }}
{% for comment in post.comment_set.all %}
{{ comment }}
{% endfor %}
{% endfor %}
To reduce the number of queries use prefetch_related to get all related comments for all posts in a single query
def posts_list(request):
all_posts = Post.objects.prefetch_related('comment_set')
return render(request, 'template.html', {'all_posts': all_posts})
I try to build a blog and this blog in the home view www.site.com consist of posts and these posts have comments, Now I Show the posts using List [] because the user has the ability to follow the content and in this list, I show the content based on the user, Now I successfully to show the posts but this post contains comments that's mean I need to get the pk of the post but as I said this post in the home view www.site.com without any extra URL that's mean as My knowledge I can't pass the pk in the def home_screen_view(request, pk) because this raise error home_screen_view() missing 1 required keyword-only argument: 'pk'
So my qustion how can I get the pk in the base url www.site.com
My view
def home_screen_view(request, *args, **kwargs):
users = [user for user in profile.following.all()]
post = []
for u in users:
p = Account.objects.get(username=u)
posts = p.post_set.all()
post.append(posts)
my_posts = request.user.post_set.all()
post.append(my_posts)
if len(post):
post= sorted(chain(*post), reverse=True, key=lambda post: post.created_date)
posts = Post.objects.filter(pk=post.pk) # here I want to get the pk of the post in order to show the comments related this post
comment = PostCommentIDE.objects.filter(post=posts)
The url
path('', home_screen_view, name='home'),
My Post Model
class Post(models.Model):
author = models.ForeignKey(Account, on_delete=models.CASCADE)
article = models.TextField(null=True, blank=True)
photo_article = models.ImageField(max_length=255, upload_to=get_poster_filepath)
created_date = models.DateTimeField(auto_now_add=True)
My Comment Model
class PostCommentIDE(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='ide_com')
author = models.ForeignKey(Account, on_delete=models.CASCADE)
content = models.TextField()
created_date = models.DateTimeField(auto_now_add=True)
The post template
{% for post in posts %}
...
#here I want to render the comments that related to spesific post
{% for comment in comments %}
{{ comments.content }}
{% endfor %}
...
{% endfor %}
I use function based view
From your home_screen_view you can remove
comment = PostCommentIDE.objects.filter(post=posts)
Instead, in your template you can do:
{% for comment in post.ide_com.all %}
{{ comments.content }}
{% endfor %}
Explanation:
Your comment model PostCommentIDE has a ForeignKey relationship with Post. This enables you to get the related comments for a post. By default you could have accessed the comments with post.postcommentide_set.all, but as you've defined a related_name attribute on that relationship, it becomes post.ide_com.all. Read more about it here: https://docs.djangoproject.com/en/3.2/ref/templates/language/#accessing-method-calls
I have models that inherit from an abstract model like this:
class ImprovementAbstraction(models.Model):
needsImprovement = models.BooleanField()
hasFallacies = models.BooleanField()
hasEmotionalDeficiency = models.BooleanField()
isNecessaryToObtain = models.BooleanField()
doesAReallyCauseB = models.BooleanField()
areAllStepsPresent = models.BooleanField()
isCauseSufficient = models.BooleanField()
areAllClausesIdentified = models.BooleanField()
isCausalityCertain = models.BooleanField()
languageIsEnglish = models.BooleanField()
isTautologyPresent = models.BooleanField()
class Meta:
abstract = True
class Assumption(MainAbstractModel, ImprovementAbstraction):
need = models.ForeignKey(Need, on_delete=models.SET_NULL, null=True)
assumption = models.CharField(max_length=500, default="", null=True)
def __str__(self):
return self.assumption
In the template I would like to display all of the "ToImprovementAbstraction" Model fields associated with the Assumption model. Is there a way to loop over all the fields in the template, something like Assumption.ImprovementAbstractionFields.all() (made up code)?
I use the built-in vars() method for that.
For example, you have an Assumption object:
assumptionObject = .models.Assumption.objects.get(pk=1)
If you use vars() method with that query object like this:
vars(assumptionObject)
it will return a dictionary containing all the field names and values as a Python dictionary.
If you only want the field names you can use it like this:
vars(assumptionObject).keys()
EDIT: I should warn you that, if you use vars() on a query object, the returned dictionary will contain a django.db.models.base.ModelState object stored in a key called _state. If you're going to use the values in a for loop or something, you should put an exception for that.
Not exactly sure what your desired outcome is, but this is the basic approach to query data from the database and render the html:
You will first have to query the data from the database like so:
Views.py
def search(request):
queryset = ToImprovementAbstraction.objects.all()
context = {
'queryset': queryset
}
return render(request, 'your_template.html', context)
Then you can use the data to render your template like so:
your_template.html
{% for item in queryset %}
<p>{{ item.needsImprovement }}</p>
[...]
[...]
{% endfor %}
If oyu have multiple models you can make multiple queries to use one/many-to-many fields in your models to link them straight away.
get the assumption object in view and render the ImprovementAbstraction through foreign key. for example:
def get_item():
queryset = Assumption.objects.all()
return render(request, 'template.html', {'queryset': queryset})
Now in your template you can access the data this way
{% for query in queryset %}
{{query.need.needImprovement}}
{{query.need.hasFallacies}}
{{...}}
{% endfor %}
This way you can display everything in one loop. Hope this gets you some idea.
Im new to django and still learning its full potential. I have two models One is the parent (GoodsReceivedNote) and the other are the items for that note (One to Many). I realize a normal ModelForm is not going to work here as I want the user to be able to enter the details for the parent as well as the children objects.
I looked in to InlineFormSets but as far as I undestood I need to create the parent object first and then assign it to my children.
Also looked at this link : http://sayhelloworld.co/create-parent-child-model-objects-in-one-form-with-django/ how ever they are using the date to get the recent parent object and add it to the child which doesnt seem the best way
GoodsReceivedNote.py
class Goodsreceivednote(models.Model):
GOODS_INWARDS = 'INWARDS'
GOODS_REJECTED = 'REJECTED'
NOTE_TYPES = (
(GOODS_INWARDS, GOODS_INWARDS),
(GOODS_REJECTED, GOODS_REJECTED),
)
rec_note_id = models.CharField(primary_key=True, max_length=20)
note_date = models.DateField()
type = models.CharField(choices= NOTE_TYPES, max_length=15, default=GOODS_INWARDS)
The Items.py
class Goodsreceiveitem(models.Model):
received_item_id = models.CharField(primary_key=True, max_length=255)
rec_note_id = models.ForeignKey(Goodsreceivednote, models.PROTECT)
item_id = models.ForeignKey(Inventory, models.PROTECT)
item_qty = models.IntegerField()
Here is a Sketch of how i expected it to look like
Thanks In Advance ! Cheers !
You can use ModelForm for note (since there is going to be only 1 note) and InlineFormSet for item (since you will allow multiple). You don't need to save note prior to items - you can save them at the same request.
Dynamic adding/deleting items require javascript and will not be covered in this answer, however it should be easy enough to understand what django expect to receive.
So, first of all you need to create ModelForm:
forms.py:
class NoteForm(forms.ModelForm):
class Meta:
model = Goodsreceivednote
fields = '__all__'
We are going to use inlineformset_factory to create InlineFormSet for items. When saving items, we have to provide parent note to foreign field.
views.py:
from django.forms import inlineformset_factory
from .models import Goodsreceivednote, Goodsreceiveitem
from .forms import NoteForm
def note_view(request):
# Create formset based on our parent model and child model. We are going to allow up to 3 items in form.
NoteFormSet = inlineformset_factory(Goodsreceivednote, Goodsreceiveitem, fields='__all__', extra=3)
# generate form and formset
form = NoteForm(request.POST or None, request.FILES or None)
formset = NoteFormSet(request.POST or None, request.FILES or None)
if form.is_valid() and formset.is_valid():
note = form.save()
for form in formset.forms:
item = form.save(commit=False)
item.rec_note_id = note
item.save()
return render(request, 'formset.html', {'form': form, 'formset': formset})
formset.html:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
{{ formset.as_p }}
<button type="submit">submit</button>
</form>
Also you don't have to specify primary keys in models - they will be automatically generated as AutoField. That will decrease some rough parts of models, since you don't have to worry about them being unique.
I am compiling a database of articles and have my model set up like this:
class articles(models.Model):
ArticleID = models.IntegerField(primary_key=True)
Title = models.CharField(max_length=500)
Author = models.CharField(max_length=200, null=True)
Journal = models.CharField(max_length=500, null=True)
Date = models.IntegerField(null=True)
Issue = models.IntegerField(null=True)
Link = models.URLField(max_length=800, null=True)
Content = models.TextField()
class Meta:
db_table = 'TEST'
def __str__(self):
return f'{self.Title}, {self.Author}, {self.Journal},{self.Date}, {self.Issue}, {self.Content}'
def get_absolute_url(self):
return reverse('article-detail', args=[str(self.ArticleID)])
The idea is pretty simple. Each meta data type (i.e. title, author) is it's own field, and the actual content of the article is in the field Content.
My view for this model:
def article_detail(request, ArticleID):
ArticleID = get_object_or_404(articles, ArticleID=ArticleID)
context = {'ArticleID': ArticleID}
return render(request, 'article_detail.html', context)
The HTML template for the view:
{% extends 'base.html' %}
{% block content %}
<div class="container">
{{ ArticleID }}
</div>
{% endblock %}
The data displayed in on the HTML page is one big block of text in one single HTML element. How can I make it so that I can use CSS to target each individual field from the model? Must I make separate models for each field (and bound them with foreign keys)?
No of course not. You can access fields with normal dot notation: ArticleID.Title, ArticleID.Author, etc.
(But you shouldn't call your context variable ArticleID; it's the whole article, not the ID. Also, Python style is to use lower_case_with_underscore for variables and attribute names.)
There is already a primary key in for every model which is called id, you don't have to explicitly declare that.
Secondly you are getting an article object with get_object_or_404 so if you use . (dot) notation you will get your desired value in your template.
Something like-
<h2>{{article.Title}}</h2>
<p>{{article.Content}}</p>
though you have to send article names instead of ArticleID in context variable.
In addition to Mr. Daniel Roseman's comment you should use class name Article instead of articles which is not pythonic.