Multiple Django records for one user - python

I want to add multiple values for a user in Django. in that a user may have several records displayed.
Records should belong to a specific user selected.
Models.py looks like :
class Medrecs(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
title = models.CharField(max_length=60, null=True)
clinician = models.ForeignKey(Clinician, on_delete=models.PROTECT)
Patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
meds = models.TextField()
def __str__(self):
return self.title
models.ForeignKey doesnt work either. It displays records to all patients but I want a specific patient/user selected. OneToOne will display for specific user but only once.
Views.py looks like:
def my_profile(request):
meds = Medrecs.objects.all()
if request.user.is_authenticated:
return render(request, 'MyDoc/my_profile.html', {'meds': meds})
else:
return redirect('MyDoc:login_patient')
And my template looks like :
{% if meds %}
{% for m in meds %}
<div class="col-sm-6 panel-primary">
<img class="logo" style="height: 35px; width: 35px; margin-right: 15px;" src="{{ user.patient.image.url }}">
<p>St.Denvers Hospital,</p><br>
<p>Healthcare is our compassion</p>
<p>{{ m.title }}</p>
<div class="panel panel-primary">
<div class="panel-heading active">
<h3 class="text-success">Doctor:{{ m.clinician }}</h3>
<p>Name: {{ m.patient }}</p>
</div>
<div class="panel-body">
<p>Medication: {{ m.meds }}</p>
</div>
</div>
</div>
{% endfor %}
{% endif %}
This works fine but i can only add one patient record and i want multiple for the same user. At the Django database it tells me theres a record for that user.
NB:/The user is also a patient.
Asking for help ..>>

You have a one to one relationship in your model which means one user to one record.
change the relationship to Foreign Key so that multiple records can go to one user.
What you need to change it to:
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="records")
and in the view you are querying all of the records which is not what you want.
Views.py
if request.user.is_authenticated:
meds = Medrecs.objects.all().filter(user=request.user)
return render(request, 'MyDoc/my_profile.html', {'meds': meds})
With this you are filtering all the records that belong to this user

Related

Display counter of likes per post with Django is not working

I want to get a variable on the views.py file that retrieves the list of likes for each post. So, then on the HTML file, I would use .count so I can get the number of items on the list and finally be displayed on the DOM.
I first made classes on models.py. There, I have 3 classes: User, Post, and Like. User is from the default User class from Django. Post is a class that gets information about the post like the author, description, and timestamp. And on the Like class, I get the user and post.
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
pass
class Post(models.Model):
author = models.ForeignKey("User", on_delete=models.CASCADE, related_name="user")
description = models.CharField(max_length=1000)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.id}: {self.author}"
class Like (models.Model):
user = models.ForeignKey("User", on_delete=models.CASCADE, default='', related_name="user_like")
post = models.ForeignKey("Post", on_delete=models.CASCADE, default='', related_name="post_like")
def __str__(self):
return f"{self.id}:{self.user} likes {self.post}"
Second, I made a function on views.py called "index". There, I get the whole list of posts (on the posts variable), then I tried to create the variable (totalLikesSinglePost), which should get the list of likes for each post.
def index(request):
posts = Post.objects.all().order_by("id").reverse()
# Pagination Feature (OMIT THIS, IF YOU WANT)
p = Paginator(posts, 10)
pageNumber = request.GET.get('page')
postsPage = p.get_page(pageNumber)
# Total likes of each post. DOESN'T WORK ⏬
for postSingle in posts:
totalLikesSinglePost = Like.objects.all().filter(post = postSingle)
return render(request, "network/index.html", {
"posts": posts,
"postsPage": postsPage,
"totalLikesPost": totalLikesSinglePost
})
Finally, on the HTML file, there I get each post with its information and the number of likes. However, the output just displays the number 0
{% for post in postsPage %}
<div class="row">
<div class="col">
<div class="card h-100" id="post-grid">
<div class="card-body">
<h5>{{ post.author }}</h5>
<div> | {{ post.timestamp }}</div>
<p>{{ post.description }}</p>
<div class="card-buttonsContainer">
<strong style="color: red">{{ totalLikesPost.count }}</strong> <!--0 IS DISPLAYED-->
</div>
</div>
</div>
</div>
</div>
{% endfor %}
And of course, after that, I created a superuser and went to admin to add some examples to the database. However, I added some new rows on the Like table but does not display the total of likes for each post.
Your totalLikesSinglePost is just a list of Like records of the last post.
Try this on your html file:
<strong style="color: red">{{ post.post_like.count }}</strong>
Because totalLikesSinglePost get override in each round of for loop. It is the total number of likes of the last post.
You need to assign this number to the post as an attribute, like
for post in posts:
post.num_likes = Like.objects.all().filter(post=post).count()
And then in your template
{% for post in posts %}
{# ... #}
{{ post.num_likes }}
{% endfor %}
However, I strongly recommend you using .annotate
from django.db.models import Count
posts = Post.objects.all().order_by('-id')\
.annotate(num_likes=Count('like'))
This will access database only once and save you a lot of time.

Field 'id' expected a number but got 'xyz'

In Models.py
class Post(models.Model):
user = models.CharField(max_length=100)
likes = models.IntegerField(default=0)
content = models.TextField()
date = models.DateTimeField(auto_now_add=True)
class Profile(models.Model):
following = models.ForeignKey('User',on_delete=models.CASCADE,related_name='following')
user = models.ForeignKey('User',on_delete=models.CASCADE,related_name='user')
def __str__(self):
return self.user
In views.py
def viewProfile(request,username):
posts = Post.objects.filter(user=username).order_by('id').reverse()
profile = Profile.objects.filter(user=username)
no_of_followers = profile.following.count()
return render(request, "network/profile.html",{
"posts":posts,
"username":username,
"no_of_followers":no_of_followers
})
In profile.html
{% extends "network/layout.html" %}
{% block body %}
<h2 style="margin-left: 20px;">Posts of {{username}}</h2>
<div class="col-sm-6">
<div class="card">
<div class="card-body">
<h5 class="card-title">Profile Details</h5>
<p class="card-text">Followers:{{no_of_followers}}</p>
<p class="card-text">Followings:0</p>
Go somewhere
</div>
</div>
</div>
{% for post in posts %}
<div class="card" style="width:70%;margin-left: 10%;margin-right: 20%;">
<div class="card-body">
<h5 class="card-title">{{post.user}}</h5>
<div class="form-group">
<p>{{post.date}}<br>{{post.content}}</p>
</div>
<p>{{post.likes}}</p>
</div>
</div>
{% endfor %}
{% endblock %}
Facing an error of Field 'id' expected a number but got 'xyz'. xyz is the username
If I replace profile = Profile.objects.filter(user=username)with profile = Profile.objects.filter(user__user=username) then I am getting the error django.core.exceptions.FieldError: Related Field got invalid lookup: user
The lookup should be:
profile = Profile.objects.get(user__username=username)
since you want to retrieve a Profile for which the user has a username that has the given username.
You probably should use .get(…) [Django-doc] here to retrieve a Profile object, not a QuerySet of Profiles.
You might want to use the get_object_or_404(…) function [Django-doc] instead, such that it returns a 404 in case no such profile exists:
from django.shortcuts import get_object_or_404
def viewProfile(request,username):
posts = Post.objects.filter(user__username=username).order_by('-id')
profile = get_object_or_404(Profile, user__username=username)
no_of_followers = profile.following.count()
return render(request, 'network/profile.html',{
'posts':posts,
'username':username,
'no_of_followers":no_of_followers
})

why are comment objects not deleted from database although the view is triggered?

I try to remove comment so, I tried the first time by the class-based view then I hashed it to try the second way by normal function to know what's going on here. so, when I try to delete the comment by ID nothing does happen it's just directing me to the web page without deleting the comment so in this case the program runs but doesn't remove the object so, what is going on here?
Note: the posts and comments on the same page and slug field on that page are following by post not comment.
if the title of the post is: new title so, the slug will be new-title depending on the post
question_view.html
<div class="user-answer">
<div class="row">
<div class="col-xs-12">
{% for comment in my_question.comment_set.all %}
<div class="comments">
<div class="col-xs-0">
<div class="avatar">
<a href="{% url 'account:view_profile' comment.username %}">
<img class="img-circle img-thumbnail" style="width:50px; height: 50px;" src="{{ comment.logo }}">
</a>
</div>
</div>
<div class="col-xs-10">
<!-- --Comment itself-- -->
<div class="user_comment">
<p>{{ comment }}</p>
<div class="fa fa-caret-left comment-arrow"></div>
</div>
<!-- start Options in comment -->
<div class="sub-options">
{% if request.user.username == comment.username %}
<!-- --Edit comment-- -->
<div class="edit-comment">
<a>Edit</a>
</div>
<!-- --Delete comment-- -->
<div class="delete-comment">
<form method="post" action="{% url 'community:delete_comment' comment.pk %}">
{% csrf_token %}
<input type="hidden" name="delete-comment" value="{{ comment.comment }}">
<input type="submit" value="delete">
</form>
</div>
{% endif %}
<!-- end Options in comment -->
<!-- --comment Date-- -->
<div style="display: inline-block;color: #8e8e8e" class="comment-date">
<p>{{ comment.date|time }}</p>
</div>
</div>
</div>
<div class="clearfix"></div>
</div>
{% endfor %}
</div>
</div>
</div>
views.py
# Delete post
# class DeleteComment(DeleteView, SingleObjectMixin):
# model = Comment
# pk_url_kwarg = 'pk'
# template_name = 'community/question_view.html'
# queryset = Comment.objects.all()
#
# def get_success_url(self):
# title = UserAsking.objects.get(title=self.object)
# slug = UserAsking.objects.get(title=title).ask_slug
# return reverse_lazy('community:question_view', kwargs={'user_slug': slug})
#
# def get_object(self, queryset=None):
# request_comment = self.request.POST['delete-comment']
# return self.get_queryset().filter(pk=request_comment).get()
def delete_comment(request, pk):
if request.method == 'POST':
comment = Comment.objects.get(pk=pk)
del comment
return redirect('community:user_questions')
urls.py
urlpatterns = [
# path('delete-comment/<int:pk>/', views.DeleteComment.as_view(), name="delete_comment"),
path('delete-comment/<int:pk>/', views.delete_comment, name="delete_comment"),
]
models.py
class Comment(models.Model):
userasking = models.ForeignKey(UserAsking, on_delete=models.CASCADE)
comment = models.TextField(max_length=500, blank=True)
date = models.DateTimeField(auto_now_add=True)
userprofile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, default=1)
name = models.CharField(max_length=30, blank=False, default='empty')
logo = models.ImageField(upload_to='images/', default='images/default-logo.jpg', blank=True)
username = models.CharField(max_length=30, blank=False, default='empty')
def __str__(self):
return self.comment
I hope if you can explain by class based-view what's happening I will appreciate that.
note that: if you could understand exactly what's happening you will know that is no error appears to me, therefore, I get no exception or traceback. thank you in advance.
Try this:
def delete_comment(request, pk):
if request.method == 'POST':
comment = Comment.objects.get(pk=pk).delete()
return redirect('community:user_questions')
Your function only deletes the object but not the database entry since you don't trigger a valid SQL operation (delete in this case).
You just delete the object comment again which was assigned previously, but you don't affect the database entry:
def delete_comment(request, pk):
if request.method == 'POST':
comment = Comment.objects.get(pk=pk)
del comment
return redirect('community:user_questions')
More on delete() in the official docu:
Deleting objects¶
Update on your comment:
You can't use Python's del statement to interact with database entries in Django.
Pythons del statement is used to delete objects initially created by Python like lists, variables, etc. etc.
In order to interact with your database in Django, you have to use the toolbox of Django's built-in Model instance which basically translates raw SQL operations into easy to use methods.
So maybe you can adapt a proper wording to highlight the differences by calling database "objects" entries and python objects: well, objects..
However, Django still offers the option to use raw SQL as fallback.

How can i add something to the database with a submit button in Django?

I'm making a grocery list web app in django and i have a page with your groceries list and i have a page with all the products you can add to your list.
every product has a button "add to list". The intention is that when you click on that button that that product automatically becomes added to the groceries list. Does someone know how to do that? thank you in advance.
The Groceries List page
The all products page
models.py
from django.db import models
# Create your models here.
class Brand(models.Model):
name = models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
class AllProducts(models.Model):
name = models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
class ShoppingList(models.Model):
product = models.ForeignKey(AllProducts, null=True, on_delete= models.SET_NULL, blank=True)
brand = models.ForeignKey(Brand, null=True, on_delete= models.SET_NULL, blank=True)
quantity = models.CharField(max_length=200, null=True, blank=True)
info = models.TextField(max_length=500, null=True, blank=True)
def __str__(self):
return self.product
The class brand is a class with all the brands of the products.
The class All_Products is a class with all the products that you can add to your groceries list.
And the class ShoppingList is a class with all the products in the groceries list.
Views.py
def home(request):
products = ShoppingList.objects.all()
context = {
'products':products,
}
return render(request, 'groceries_list/home.html', context )
def all_products(request):
all_products = AllProducts.objects.all()
context = {
'products':all_products,
}
return render(request, 'groceries_list/all_products.html', context)
The home function is the function that handels the groceries list page an the all_products function is the function that handels the page with all the product you can add to your list.
groceries list template
{% extends "groceries_list/base.html" %}
{% block content %}
<div class="card">
<div class="card-body">
<div class="card m-1 text-white">
Add Grocery
</div>
{% for product in products %}
<div class="item-row">
<div class="card m-1 text-white" style="background-color: #9BD6E0;">
<div class="card-body">
<a class="btn btn-sm btn-info" href="{% url 'update_gorcery' product.id %}">Update</a>
<a class="btn btn-sm btn-danger" href="{% url 'delete_gorcery' product.id %}">Delete</a>
<span class="text-dark"><strong>{{product.product}}</strong> {{product.quantity}} </span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
all products template
% extends "groceries_list/base.html" %}
{% block content %}
<div class="card">
<div class="card-body">
<div class="card m-1 text-white">
Add Product
</div>
{% for product in products %}
<div class="item-row">
<div class="card m-1 text-white" style="background-color: #9BD6E0;">
<div class="card-body">
<button type="submit" class="btn btn-success btn-sm ">Add To List</button>
<span class="text-dark ml-3 text-center"><strong>{{product.name}}</strong>
<a class="btn btn-sm btn-danger float-right" href="{% url 'delete_product' product.id %}">Delete</a>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
The site may have many users using it at the same time, so you should arrange for a way to identify the particular user who adds the item to the shopping list. The easiest way to do this is to create an authentication system (You can use as-is or extend the User model) from django.auth.models
Looking at your views, as they are, both the home() and and all_products() view are rendering the same context, which definitely can't be what is in the cart (for the home view).
A way to handle this would be to make your ShoppingList model in a way that it includes a field for the customer. The customer would be the user making the request.
In the all_products.html page, you can create a form with a hidden field that you pre-populate with the product.id and the 'add to list' button as a submit button for this form.
When a user clicks 'add to list', the form gets posted to a url that invokes the responsible view. In that view, you create a 'ShoppingList object' (an instance of the ShoppingList model that you created in models) with values of the product.id that was posted by the form and the customer as request.user (the user making the request).
Just a few random tips:
In your ShoppingList model, you are defining quantity as a CharField but quantity is best defined as an IntegerField. Also, there is no need to use both blank=True and null=True arguments. I personally like to use blank=True only due to safety reasons that I won't talk about here.
I would also recommend that you revise the naming systems for your models and views.
In summary:
Add field customer to the ShoppingList model.
Make field product a CharField.
Make a form with a hidden field that posts back the product.id when a
user clicks 'add to list'.
Handle the post request by making a ShoppingList object.
Consider making quantity an IntegerField.

Django Getting Data From Foreign Key

Im a newbie working on a news site (or at least trying to, a lot of "problems" in the last few days lol ) trying to learn Django the best I can.
This is what I want to do :
I have an Article Model, it used to have 6 image fields that I used to send to the template and render the images, each image field had its own name and all was well in the world.
Then I got tasked with puting the Article images in a separate Image model.
So I did this :
class Article(models.Model):
title = models.CharField('title', max_length=200, blank=True)
slug = AutoSlugField(populate_from='title', default="",
always_update=True, unique=True)
author = models.CharField('Author', max_length=200, default="")
description = models.TextField('Description', default="")
is_published = models.BooleanField(default=False)
article_text = models.TextField('Article text', default="")
pub_date = models.DateTimeField(default=datetime.now, blank=True)
article_category = models.ForeignKey(Category, on_delete="models.CASCADE", default="")
def __str__(self):
return self.title
class ArticleImages(models.Model):
article = models.ForeignKey(Article, on_delete="models.CASCADE", related_name="image")
image = models.ImageField("image")
name = models.CharField(max_length=50, blank=True)
But so far I wasnt able to access my images in my template using
{{ article.image.url }} or {{ article.image.image.url }}
or any other combination. Why is that ?
Did I set up my models correctly ? One person suggested that I should change the model field from ForeignKey to OneToOneField, but I didn't get much feedback on why and how ?
So, how would I make a for loop that loops through the Articles model and then gets the related images for each Article ? I essentially want it to behave like I still have the 6 different fields like I did before. ( I have to do it this way, it's a part of the task ).
here are my views and my "index" template that I used to loop through the Articles and display 6 latest news on my home page. (please ignore the tags,I am aware they aren't working like this..the template is just so you can understand what I am talking about )
my views.py:
class IndexView(generic.ListView):
template_name = 'news/index.html'
context_object_name = 'latest_article_list'
def get_queryset(self):
return Article.objects.all()
class CategoryView(generic.ListView):
template_name = 'news/categories.html'
context_object_name = 'category'
def get_queryset(self):
return Article.objects.filter(article_category__category_title="Politics")
class ArticlesView(generic.ListView):
context_object_name = 'latest_article_list'
template_name = 'news/articles.html'
paginate_by = 5
def get_context_data(self, **kwargs):
context = super(ArticlesView, self).get_context_data(**kwargs)
context['categories'] = Category.objects.all()
return context
def get_queryset(self):
category_pk = self.request.GET.get('pk', None)
if category_pk:
return Article.objects.filter(article_category__pk=category_pk).order_by("-pub_date")
return Article.objects.order_by("-pub_date")
def article(request, article_id):
article = get_object_or_404(Article, pk=article_id)
context = {'article': article,
'article_category': article.article_category.category_title}
return render(request, 'news/article.html', context)
template that I used with my old model :
{% for article in latest_article_list %}
<img class="single-article-img" src="{{ article.image.name.url }}" alt="">
<div class="container row">
<!-- Start Left Blog -->
<div class="article mt-10 col-md-4 col-sm-4 col-xs-12">
<div class="single-blog" style="margin:10px auto;">
<div class="single-blog-img">
<a href="{% url 'news:article' article.id %}#article-title">
<img class="for-imgs" src="{{ article.image.url }}" alt="">
</a>
</div>
<div class="blog-meta">
<span class="date-type">
<i class="fa fa-calendar"></i>{{ article.pub_date }}
</span>
</div>
<div class="xx blog-text">
<h4>
{{ article.title }}
</h4>
<p>
{{ article.description|truncatewords:30 }}
</p>
</div>
<span>
Read more
</span>
</div>
</div>
{% endfor %}
Thank you !
You need to loop over the images as you have many images against a single article object. You can have something like below to show images in your template:
{% if latest_article_list.articleimages %}
{% for articleimage in latest_article_list.articleimages.all %}
<img src="{{ articleimage.image.url }}" class="d-block w-100" alt="...">
{% endfor %}
{% endif %}

Categories