Display query set object in django template - django

I have a model Post that I'm trying to display all the posts onto a template. I'm including the post.html onto the home.html....
I found a similar problem to my question but the objects still are not getting displayed link
I firt tried the to use python manage.py shell to create an object. So first I did this.
Post.objects.all()
<QuerySet [<Post: test>, <Post: admin>]>
then I tried to create a new posts.
Post.objects.create(user="test", content="New comment")
but got this error:
ValueError: Cannot assign "'test'": "Post.user" must be a "User" instance.
Tried to troubleshoot and couldn't resolve it. So I just decided to write the code in the posts/views.py and it didn't work as well. I figure this is the root of my problem why the objects aren't showing up in the templates.
This is my posts/posts.views
def posts_list(request):
# if request.user.is_authenticated():
queryset = Post.objects.all()
context = {
"object_list": queryset,
"user": "username"
}
return render(request, "posts.html", context)
This is my templates/post.html
<!DOCTYPE html>
<html lang="en">
<body>
<h1>What's on your mind, {{ user }}</h1>
{ % for obj in object_list %}
{{obj.user}}<br/>
{{obj.content}}<br/>
{{obj.timestamp}}<br/>
{% endfor %}
</body>
</html>

You have asked two questions here. I'll answer both of them below:
Displaying your posts
First, you need to make sure that you are passing a user object to your template. Assuming that user info is stored in request.user, you can do so as follows:
views.py:
def posts_list(request):
if request.user.is_authenticated:
user = request.user
queryset = Post.objects.all()
context = {
"object_list": queryset,
"user": user
}
return render(request, "home.html", context)
home.html:
<html>
<h1>Homepage</h1>
{% if user.is_authenticated %}
<h1>What's on your mind, {{ user }}</h1>
{ % for obj in object_list %}
{{obj.user}}<br/>
{{obj.content}}<br/>
{{obj.timestamp}}<br/>
{% endfor %}
Logout
{% endif %}
</html>
Adding a post for a user
You need to get a user object to pass to your creation method, rather than using the string "test". The reason your attempt is failing is because you are passing the function a string ("test") where it is expecting a user object.
This line gets a user (arbitrarily grabs the first one in your list):
u = User.objects.all()[0]
This line imports the datetime module, which you'll need to generate date and datetime objects for your create method:
import datetime
And this line creates a post for that user:
Post.objects.create(user=u, content="New comment", publish=datetime.date.today(), updated=datetime.datetime.now(), timestamp=datetime.datetime.now())

Normally in request, django automatically add requested user. If that user has related permission to add new Post then following code should work
Post.objects.create(user=request.user, content="New comment")

When you are creating a foreign key, you are referring a model.
suppose there are two models A and B. B has following fields - x, y, z. Now, x field is a foreign key, which is referring model A.
Now whenever you want to create an object of B, then the value of x field should be an object of A. Little bit like this -
post1 = Post(user = an object of User Model, content = "your value")
so create an object of User first. Then write it there. otherwise it will give error.

Related

Pass other object/data into Flask Admin model view edit template

I'm extending the edit template for a ModelView so that I can show some other information from the database that is relevant for determining how to edit the record in this view. I know how to extend the template and get it to work, but I can't figure out how to query an object and use it in the template.
Also I need to use the value from the model/record in querying the new object I need to pass.
Here is my code from init.py:
class MilestoneView(ModelView):
edit_template = '/admin/milestone_model/milestone_edit.html'
can_delete = True
#i need something like this to work:
referrals = Referral.query.filter_by(email=model.email)
#then i need to pass referrals into the template
admin = Admin(app, name="My App", template_mode='bootstrap3')
admin.add_view(MilestoneView(Milestone, db.session, name='Milestones'))
Then from milestone_edit.html, I want something like this to work:
{% extends 'admin/model/edit.html' %}
{% block body %}
{{ super() }}
{% for r in referrals %}
<p>{{ r.name }}</p>
{% endif %}
{% endblock %}
But of course the referrals object is not available to use in the template. How do I customize this ModelView in order to pass this object in from the init file? I've reviewed the available posts on this subject(ish) on here and haven't found an answer. Thanks in advance.
Override your view's render method, see code on Github, and test if the view being rendered is the edit view. Now you can inject any data into the kwargs parameter. For example:
class MilestoneView(ModelView):
def render(self, template, **kwargs):
# we are only interested in the edit page
if template == 'admin/model/milestone_edit.html':
# Get the model, this is just the first few lines of edit_view method
return_url = get_redirect_target() or self.get_url('.index_view')
if not self.can_edit:
return redirect(return_url)
id = get_mdict_item_or_list(request.args, 'id')
if id is None:
return redirect(return_url)
model = self.get_one(id)
if model is None:
flash(gettext('Record does not exist.'), 'error')
return redirect(return_url)
referrals = Referral.query.filter_by(email=model.email)
kwargs['referrals'] = referrals
return super(MilestoneView, self).render(template, **kwargs)
Note how the model is retrieved. This is a direct copy of the code in method edit_view code. Adjust the code for your use-case.
Use the variable referrals in your edit Jinja2 template.
The render method is called in the following routes for each view:
'/' - i.e. the list view code
'/new/' - code
'/edit/' - code
'/details/' - code

default data type of primary keys in models (django), The current path, url '/app' didn't match any of these

As far as I know, the default data type of id is integer for models in Django.
For example, if I have such a model inside my models.py file, Django sets a id(primary key) for every instance of it and Django increments it automatically like 1,2,3 etc. :
class AuctionListing(models.Model):
name = models.CharField(max_length=200)
url = models.URLField()
def __str__(self):
return f"{self.name}"
Since it sets id(primary key) automatically as a data type of integer, I can create such a url in the url.py file :
path("<int:listing_id>", views.listing, name="listing")
And my views.py file:
def index(request):
return render(request, "auctions/index.html", {"auctionList":AuctionListing.objects.all()} )
also, index.html file :
{% for listing in auctionList %}
<img src = "{{listing.url}}" alt = "{{listing.name}}">
{% endfor %}
The issue with this, when it passes listing.id to the path("int:listing_id", views.listing, name = "listing"), it doesn't pass id as integer but as str. That's why, path doesn't accept it since it is int:listing_id and when I go to the page, it gives me this error : "
The current path, url 'listing' listing.id, didn't match any of these".
When I change int:listing_id to str:listing_id it works. I wonder if the default data type of id is a string data type in Django? As far as I know it should be a data type of integer. Can someone explain please?
By the way, I am inheriting from AbstractUser.
DB is sqlite3
Yes, the default object primary key data type in django is int but if you want to access it you should either declare your own primary key field or use the default name which is pk, in that case your urls should look something like this:
path("", views.listings, name="listings"),
path("<int:pk>", views.listing, name="listing")
and your views something like this:
def index(request):
listings = AuctionListing.objects.all()
return render(request, 'listings.html', {'listings': listings'}
def listing(request, pk):
listing = AuctionListing.objects.get(pk=pk)
return render(request, 'listing.html', {'listing': listing'}
and in your listings.html:
{% for listing in listings %}
{{ listing.name }}
{% endfor %}

Django: display object's another field from template tag?

I have objects in my database, each object has two values(fields): 'id' and 'name'.
I want to request my model from template tags to display another field of the object, when first one is given.
Example.
Model: Fruits
Objects:
Name:Banana ID:1
Name:Apple ID:2
Name:Orange ID:3
How do I make a request from my template tag to ask something like: 'display name of the object with ID=1' or 'display ID of the object named Orange'?
Dos here: A shortcut: get_object_or_404().I made some modifications to make it easier to understand.
from django.shortcuts import get_object_or_404, render
from .models import Question
# ...
def detail(request, question_id):
# get your object here
question = Question.objects.all()
return render(request, 'polls/detail.html', {'question': question})
And in templetes
{% for qu in question %}
<li>{{ question.question_text }}</li>
{% endfor %}
So I've read through the documentation and figured out how to complete the task. I had to use Custom template tags.
This is how. We need to create a folder 'templatetags' in django app's directory (myapp/templatetags/) and two files there: '__init__.py' (which is empty) and 'mytags.py' (that is where we create a custom template tag).
In this example objects have 2 fields: 'id' and 'name'. Objects are stored in a model named 'Fruits'.
mytags.py:
from myapp.models import Fruits
from django import template
register = template.Library()
#register.filter
def get_fruits_name(fruits, id):
fruits = Fruits.objects.get(id=id) # get the object with given id, the id is passed from template.html through custom template tag
return fruits.name # return the object's name
template.html:
{% load mytags %} # loads mytags.py with our custom template tag
{{ fruits|get_fruits_name:1 }} # displays the name of a fruit with id '1' (in this case, 'Banana')

how do I make a query of a user's uploaded files

I'm a django newbie trying to finish a upload/download app. I am Using django-registration-redux for user reg/auth and have the following simple model. I've read the docs but haven't been able figure out how to query on a User's related fields namely, fields of a model with foreignkey to User.
here's my model:
from django.contrib.auth.models import User
FileUploads(models.Model):
owner = models.ForeignKey(User)
docfile = models.FileField(nul=True)
docfileuuid = models.UUID()
My question being: Having a specific username, How can I query the list of his/her docfiles?
What I want to accomplish is when the user logs in and navigates through a view let's call it 'localhost:/yourfiles', s/he can be provided a list of his files.
In case of having no owner with foreign key to user, I used the following code to retreive the path to the all uploaded files:
obj = FileUploads.objects.all
uploads = [i.docfile for i in]
Now instead of all the docfiles, I want the ones that belong to the logged-in user.
I read the docs and tried things like:
obj = User.objects.all()
obj.fileuploads_set.all()
But no luck
When a user logs in your application, you do have user object in request.user
In your views.py,
def file_list_view(request):
# This gives you list of file objects.
files = FileUploads.objects.filter(owner=request.user)
return render_to_response('my_template.html', {'files': files})
In your template file
<ul>
{% for file in files %}
<li>{{ file.file_name }}</li>
{% endfor %}
</ul>
Hope this helps.
To get all files belong to a user by querying the username, do:
FileUploads.objects.filter(owner__usename='amir')
In your views.py, you would do:
uploads = FileUploads.objects.filter(owner=request.user)
You can create a simple function view with a context dictionary. Filter the files in your model by the current user logged in which you can get by request.user. And then in your template use a for loop to print all file urls that user has, and by using the {% empty %} template tag to show a message whenever a user doesn't have any files uploaded.
views.py
#login_required
def userfiles(request):
context_dict = {}
files = FileUploads.objects.filter(owner=request.user)
context_dict['files'] = files
return render(request, 'users_files.html', context_dict, )
the template:
{% for file in files %}
file.docfile.url
{% empty %}
You don't have any files uploaded yet.
{% endfor %}

how can I ensure a user will not delete another user object in my website [Django]

I wrote a function that allows the user to delete his article on a blog website. The problem is, if he plays a little with the url, he can access to another article and delete it.
What is the common strategy to avoid such cases with django?
here are the codes I wrote for the fonction:
views.py
def delete_article(request, id):
deleted = False
logged_user = get_logged_user_from_request(request) #that line allow to ensure that the user is connected. I use the session to achieve that instead of extending the User model
offer = get_object_or_404(Offer, id=id)
if request.method == 'POST':
offer.delete()
deleted = True
return render(request, 'offers/delete_article.html', locals())
urls.py
urlpatterns = patterns('article.views',
url(r'^send_article$', 'send_article', name='send_article'),
url(r'^my_articles$', 'show_my_articles', name='my_articles'),
url(r'^article/(?P<id>\d+)$', 'read', name='read'),
url(r'^articles$', 'show_articles', name='articles'),
url(r'^search_article$', 'search', name='search'),
url(r'^delete_article/(?P<id>\d+)$', 'delete_offer', name='delete_offer'),
)
delete_article.html
{% if not deleted %}
Hey, are you sure you want to delete {{ article.title }}?
<form method="POST">
{% csrf_token %}
<button type="submit" class="deleting_offer_button">delete</button>
</form>
{% elif deleted %}
<p>the article was successfully deleted</p>
get back to the homepage<br />
{% endif %}
As you can see, if the user change the numer of the id in the url, he can delete other article when he is directed to the confirmation of deleting page.
What webmasters are doing to ensure users cannot interfere with objects of other users?
HttpResponseForbidden can be used here which uses a 403 status code. A 403 response generally used when authentication was provided, but the authenticated user is not permitted to perform the requested operation.
Assuming you have author as an foreign key in Offer model, you can change your views like this:
In your views.py you have to import :
from django.http import HttpResponseForbidden
And then in your delete_article method use this code
offer = get_object_or_404(Offer, id=id)
if offer.author != request.user:
return HttpResponseForbidden()
When you get the article/offer. Make sure that the owner of that article is the authenticated user.
I'm not sure what your models look like but it would be something like
offer = get_object_or_404(Offer, id=id, author=logged_user)
This way if they don't own the article, it will 404