I have relation of Project between Tags and a Project can have multiple tags, But I am unable to display the tags data in my template, I am trying to display data according to tag slug. But I ma getting error, Please let me know how I can display Tags data in my Template.
Here is my urls.py file...
path('tag/<tag_slug>', views.projecttag, name='projecttag'),
here is my `models.py file...
class Tags(models.Model):
project = models.ForeignKey(Project, null=True, blank=True, related_name='ProjectTags', on_delete=models.CASCADE)
tag_name = models.CharField(max_length=64, null=True, blank=True)
tag_slug = models.SlugField(max_length=64, null=True, blank=True)
here is my views.py file...
def projecttag(request, tag_slug):
tag = get_object_or_404(Tags, tag_slug=tag_slug)
project = Project.objects.filter(ProjectTags=tag)
context = {'tag':tag, 'project':project}
template_name = 'pages/tags.html'
return render(request, template_name, context)
here is my tags.html file...
{% for property in project %}
<div class="single-property-box">
{{property.name}}
</div>
{% endfor %
According to my understandings, you want to display tags that are connected with your 'project' class. As you explain that a project can have multiple tags, so the 'ProjectTags' field from your 'Project' class must be multi-valued. But when you are filtering Projects in projecttag view, you are just checking ProjectTags=tag. Here tag is a single object. So instead you should check for ProjectTags__in=tag.
And if you already declared Tags class as ManyToManyRelation in Project class then there is no need to create Foreign Key constraint in tags class. As you didn't upload Project Class, so I don't have any idea about how you are relating tags class with it.
Related
Can't figure out where my mistake is. Not able to map through to display the list of blog comments. I'm using Django and react. From the code below, I tried to assess each blog post with comments using foreign key. But I'm not able to get the comment property from the blog. If I do something like {blog.title} I get the title of the blog back on the browser. Since comments are associated with each post I try to get different properties of comment from the blog object (just as I specified in the code below) but the value I'm getting is undefined. And have the following blog post and blog comment models:
class BlogComment(models.Model):
post = models.ForeignKey(BlogPost, on_delete=models.SET_NULL, related_name="post_comment", null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="user_comment", null=True)
name = models.CharField(max_length=200, null=True, blank=True)
comment = models.TextField(null=True, blank=True)
dateCreated = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.user.username)
class BlogPost(models.Model):
...
author = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE)
body = models.TextField()
dateCreated = models.DateTimeField(auto_now_add=True)
And the serializers for both models are:
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = BlogComment
fields = '__all__'
class BlogPostSerializer(serializers.ModelSerializer):
comments = serializers.SerializerMethodField(read_only=True)
class Meta:
model = BlogPost
fields = "__all__"
def get_comments(self, obj):
comments = obj.comment_set.all()
serializer = CommentSerializer(comments, many=True)
return serializer.data
The endpint of comment is path('posts/<str:pk>/comment/', CreateCommentView, name="create-comment"),.
The endpoint is working. I'm able to add comment to posts both from the front end. The error comes when I try to map through the
comments for each post. Get the error: AttributeError: 'BlogPost' object has no attribute 'comment_set'.
Here is the code I'm using to map through to display all the blogs of a particular post in the blog details page in react. I'm assess each blog there:
<h2>{blog.title}</h2>
<img src={blog.image} />
<div variant='flush'>
{blog.comments.map((comment) => (
<div key={comment.id}>
<strong>{comment.name}</strong>
<p>{comment.dateCreated}</p>
<p>{comment.comment}</p>
</div>
))}
</div>
Here is the code I'm using to map through to display all the blogs of a particular post in the blog details page in react. If I do not map the error does not come up and I'm able to add comment. However, in order to display the comments under each blog post I map through. How do I fix this?
You need to use post_comment:
comments = obj.post_comment.all()
You declared it here:
post = models.ForeignKey(BlogPost, on_delete=models.SET_NULL, related_name="post_comment", null=True)
related_name is used as a name for Django relation. See more here.
But changing post_comment with something else would be a better solution for me.
I have this model:
class BlogPost(models.Model):
author = models.CharField(max_length=64, default='Admin')
image = models.ImageField(blank=True, null=True)
title = models.CharField(max_length=255)
caption = models.CharField(max_length=500)
content = RichTextUploadingField()
# todo support for tags
tags = models.CharField(max_length=255, default='travel') #todo
date_created = models.DateField()
Now in tags field, I want to give multiple strings like #tips, #travel, etc on the same field. What I want is there should be like an add or increment tag, which when I click will show another tag field appears on the admin form and the user can adder another tag.
My backend is not on the regular HTML page. I have customized the default Django admin page for the backend using the material package. That is I cant use button tag and all.
How can I achieve this?? I have an image attached which explains better.
Image here
You can create another model called Tag and connect it to your BlogPost like this:
class Tag(models.Model):
text = models.CharField(max_length=244, default='travel')
blog_post = models.ForeignKey(BlogPost, on_delete=models.CASCADE, related_name='tags')
Then if you want to acces tags of a certain post in a view you would use:
blog_post = BlogPost.objects.get(pk=pk) # query the blog post you want the tags to
tags = blog_post.tags.all() # get the tags
Then simply add a form to each blog post where you would add a tag and save it to the related post. I'm not sure how you would do it an an admin interface though.
I have a Django app and am trying to make some specific model information changeable while the site is loaded. For example, I'd like to be able to change certain images on pages (banners and such) based on changes I make on the admin panel of Django. Additionally, I'd like to create a list of prepopulated migrations for my social media links that can be editable in a django admin page. My specific instance of this is for all of my social media links. I'd like to put my social media link in a model 'Facebook Url" = 'www.facebook.com/mypage. I would then like to put these links throughout the page using dot notation {{ project_settings.facebook.url }} for example. What is the easiest way to do this. I don't think I want to put the context in all of the views because I would have to do that for every page I want this to be available. In the case of my footer it is on every page. The background images are also on several different pages.
I've done what you're trying to do by creating CustomText and CustomImage models which look like the following:
class CustomText(models.Model):
name = models.SlugField()
plain_text = models.TextField("Plain/Markdown Text", blank=True)
html_text = models.TextField("HTML Text", blank=True)
auto_render = models.BooleanField("Render to HTML using Markdown (on save)", default=True)
(... implementation of text->html omitted )
class CustomImage(models.Model):
name = models.SlugField()
description = models.TextField("Description", null=True, blank=True)
image = models.ImageField("Custom Image", upload_to="custom_images/", null=True, blank=True)
Then I added myapp/templatetags/custom_resources.py, which are a pair of template tags to retrieve the text or image from those models:
from django import template
from django.utils.safestring import mark_safe
from myapp.models import CustomImage, CustomText
register = template.Library()
#register.simple_tag
def custom_image(image_name):
cimage = CustomImage.objects.filter(name=image_name).first()
return cimage.image.url if cimage else "custom_image_%s_not_found" % image_name
#register.simple_tag
#mark_safe
def custom_text(text_name):
text = CustomText.objects.filter(name=text_name).first()
return text.html_text if text else "Custom text <%s> not found." % text_name
Finally, in your templates, load the templatetags, and then use the template tag with the appropriate slug for the resource you want.
{% load custom_resources %}
...
{% custom_text 'custom_text_slug' %}
I'm working on a fairly simple library project in Django, here are my models, a book can have many copies and each copy can have many loans.
class Author(models.Model):
name = models.CharField(max_length=200, unique=True)
class Book(TimeStampedModel):
isbn = models.CharField(max_length=13, primary_key=True)
title = models.CharField(max_length=200, db_index=True, unique=True)
authors = models.ManyToManyField('Author', related_name='books')
#property
def is_available(self):
"""Returns True if the Book has any available copies"""
return self.copies.exclude(loans__returned=False).exists()
class BookCopy(models.Model):
book = models.ForeignKey('Book', related_name='copies')
class Loan(models.Model):
start_date = models.DateField()
end_date = models.DateField()
returned = models.BooleanField(default=False)
customer = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True,
null=True, related_name='loans')
book_copy = models.ForeignKey(
'BookCopy', on_delete=models.CASCADE, related_name='loans')
I have a fairly simple view containing a list of books
def book_list(request):
book_list = Book.objects.prefetch_related('authors', 'copies__loans')
return render(request, 'books/book_list.html', {'books': books})
To figure out if a book is available I've written the property is_available inside the Book model. However when I call this property inside my template with the following:
{% for book in books %}
{% if not book.is_available %}
-- Template stuff --
{% endif %}
{% endfor %}
According to Django Debug Toolbar I end up with a duplicate query for every Book in the queryset
Reading the Django documentation for prefetch related there's a section discribing the behaviour which I think may be the culprit
Remember that, as always with QuerySets, any subsequent chained methods which imply a different database query will ignore previously cached results, and retrieve data using a fresh database query.
How would I prevent these duplicate queries from occuring?
I am trying to create a delete function for my Workout model.
This is the model:
class Workout(models.Model):
workoutID = models.AutoField(primary_key=True)
name = models.CharField(max_length=40)
created_by = models.ForeignKey(User)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def delete(self):
return reverse("delete_workout", kwargs = {'workout_id': self.workoutID})
Next I have the view:
def delete_workout(request, workout_id):
workout = get_object_or_404(Workout, workoutID = workout_id)
print(workout)
if request.user != workout.created_by:
return HttpResponse('Not ur workout')
else:
workout.delete()
return HttpResponseRedirect('/')
This is the url:
url(r'^(?P<workout_id>\d+)/delete/$', views.delete_workout, name='delete_workout'),
And finally the html:
<a href='{{ instance.delete }}'>
<button>Delete Workout</button>
</a>
I'm not getting any errors in the console, which is why I don't know what is going wrong.
You are overriding delete method of the class just for getting the delete url. You will get the url by url function in the template like {% url delete_workout instance.workoutID %}. So remove the delete function from the model change your html href url. Leave the view and url as the same. No issues there
class should be
class Workout(models.Model):
workoutID = models.AutoField(primary_key=True)
name = models.CharField(max_length=40)
created_by = models.ForeignKey(User)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
And your html should be
<a href='{% url delete_workout instance.workoutID %}'>
<button>Delete Workout</button>
</a>
NOTE: django model itself adds id for each table, so you dont have to specify it as you did workoutID = models.AutoField(primary_key=True).
By default each model will have a id field just like id = models.AutoField(primary_key=True)
If you consider removing the workoutID then the model becomes
class Workout(models.Model):
name = models.CharField(max_length=40)
created_by = models.ForeignKey(User)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
and the html will be
<a href='{% url delete_workout instance.id %}'>
<button>Delete Workout</button>
</a>
Django has all the tools for you under the hood. Don't reinvent the wheel. You can refactor and simplify your code.
First remove the method delete in Workout.
Second, replace your function-based-view with a class-based-view:
from django.views.generic.edit import DeleteView
from django.urls import reverse_lazy
from django.http import Http404
from .models import Workout
class WorkoutDeleteView(DeleteView):
model = Workout
success_url = reverse_lazy('delete_workout')
def get_object(self):
obj = super().get_object()
if obj.created_by != self.request.user:
raise Http404
return obj
A workout can be deleted only by its author. In success_url you specify the target where the user should be redirected after deleting.
Just adapt slightly your urls.py (pay attention to the emphasised part):
url(r'^(?P<pk>\d+)/delete/$', views.WorkoutDeleteView.as_view(), name='delete_workout'),
EDIT:
You can name your views as you please, however it would be better to follow already well established conventions. Thus the names for the class based views should be workout-list, workout-detail, workout-create, workout-update and workout-delete.