Building cascade structure - python

I just want to build a cascade structure like Category-Subject-Post in my project.
Here is my code:
models.py:
class Category(models.Model):
category_name = models.CharField(max_length=60, unique=True)
slug_category = models.SlugField(unique=True)
def get_absolute_url(self):
return reverse("skill:subjects", kwargs={"slug_category": self.slug_category})
class Subject(models.Model):
category = models.ForeignKey(Category)
subject_name = models.CharField(max_length=100, unique=True)
slug_subject = models.SlugField(unique=True)
def get_absolute_url(self):
return reverse("skill:subject", kwargs={
"slug_category": self.category.slug_category,
"slug_subject": self.slug_subject
})
class Post(models.Model):
subject = models.ForeignKey(Subject)
...
views.py:
def index(request):
context = {
'category_it': Category.objects.filter(class_name='IT'),
'category_ps': Category.objects.filter(class_name='PS'),
'category_ac': Category.objects.filter(class_name='AC'),
'category_tc': Category.objects.filter(class_name='TC'),
'category_sc': Category.objects.filter(class_name='SC'),
'category_ss': Category.objects.filter(class_name='SS'),
}
return render(request, 'skill/index.html', context)
class SubjectsView(generic.ListView):
model = Subject
queryset = Subject.objects.all()
template_name = "skill/subjects.html"
class SubjectView(generic.ListView):
model = Post
queryset = Post.objects.all()
template_name = 'skill/subject.html'
urls.py:
url(r'^$', views.index, name='index'),
# /programming
url(r'^(?P<slug_category>[\w-]+)/$', views.SubjectsView.as_view(), name='subjects'),
# /programming/git
url(r'^(?P<slug_category>[\w-]+)/(?P<slug_subject>[\w-]+)/$', views.SubjectView.as_view(), name='subject'),
# /programming/git/43121
url(r'^(?P<slug_category>[\w-]+)/(?P<slug_subject>[\w-]+)/(?P<pk>[0-9]+)/$', views.post, name='post'),
]
templates:
index.html:
{% for category in category_it %}
{{ category }}
{% endfor %}
subjects.html:
{% for object in object_list %}
<h4>{{ object }}</h4>
{% endfor %}
I don't know what query I need for that and where(views or template), I tried and hardcoded it (index in views.py and template but 6times larger) but can't afford it on the next step because of the scope.
I need categories in index.html, list of subjects belonging to particular category in subjects.html and posts belonging to their subject in subject.html. Can you please help me with finding the working solution

This site is invaluable to work your way around Class Based Views (ListView)
I think you need to override the get method, something like this:
class SubjectsView(generic.ListView):
...
def get(self, request, *args, slug_category=None, **kwargs):
if slug_category:
self.queryset = Subject.objects.filter(category__slug_category=slug_category)
super(SubjectsView, self).get(request, *args, slug_category=slug_category, **kwargs)

queryset = Subject.objects.get(category=parametrocategoria)
queryset = Post.objects.get(subject=parametrosubjet)
You simply choose to perform query

Related

models.py order of the models gives NameError: name 'Category/Post' is not defined

I'm new to Django so this is probably a dumb question but,
when I put the class Category model above the class Post model I get an
NameError: name 'Post' is not defined error.
but when I try to put class Category model underneath the Post model (as in the code here) I get
categories = models.ManyToManyField(Category)
NameError: name 'Category' is not defined error.
models.py
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE) #if is deleted than delete their posts
location = models.CharField(max_length=100, default="")
tags = TaggableManager()
likes = models.ManyToManyField(User, related_name='blog_posts')
categories = models.ManyToManyField(Category)
def total_likes(self):
return self.likes.count()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Category(models.Model):
post = models.ForeignKey(Post, related_name="categories")
name = models.CharField(max_length=20)
def __str__(self):
return self.name
admin.py
from django.contrib import admin
from .models import Post, Comment, Category #, Konum
# Register your models here.
admin.site.register(Post)
admin.site.register(Comment)
admin.site.register(Category)
#admin.site.register(Konum)
some of the code
<form method="GET" action=".">
<div class="form-group col-md-4">
<label for="category">Category</label>
<select id="category" class="form-control" name="category">
<option selected>Choose...</option>
{% for cat in categories %}
<option value="{{ cat }}">{{ cat }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">Search</button>
</form>
views.py
def home(request):
context = {
"posts": Post.objects.all()
}
return render(request, 'blog/home.html', context)
#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------
#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------
#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------
#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------
#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------
#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------#--------------------------------------------------------------------------------------------------------------------------------------
#--------------------------------------------------------------------------------------------------------------------------------------
def filter(request):
qs = Post.objects.all()
categories = Category.objects.all()
id_exact_query = request.GET.get('id_exact')
title_or_author_query = request.GET.get('title_or_author')
category = request.GET.get('category')
if is_valid_queryparam(category) and category != 'Choose...':
qs = qs.filter(categories__name=category)
context = {
'posts': qs,
'categories': Category.objects.all()
}
return render(request, 'blog/home.html', context)
class PostListView(ListView):
model = Post
template_name = 'blog/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 199
class UserPostListView(ListView):
model = Post
template_name = 'blog/user_posts.html'
context_object_name = 'posts'
paginate_by = 199
def get_queryset(self):
return Post.objects.filter(author = user).order_by('-date_posted')
urls.py
from django.urls import path, re_path
from .import views
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView, PostDeleteView, UserPostListView, TagIndexView, LikeView #, LocationPostListView
urlpatterns = [
path('', PostListView.as_view(), name="blog-home"), #has a empty strting bc its already processed blog part in main urls
path('user/<str:username>', UserPostListView.as_view(), name="user-posts"),
#--------------------------------------------------------------------------------------------------------------------------------------
#path('location/<str:loc>', LocationPostListView.as_view(), name="location-posts"),
#--------------------------------------------------------------------------------------------------------------------------------------
path('post/<int:pk>/', PostDetailView.as_view(), name='post-detail'),#pk means primary key like post 1 post 2 etc
path('post/new/', PostCreateView.as_view(), name='post-create'),
path('post/<int:pk>/update/', PostUpdateView.as_view(), name='post-update'),
path('post/<int:pk>/delete/', PostDeleteView.as_view(), name='post-delete'),
path('about/', views.about, name="blog-about"),
#--------------------------------------------------------------------------------------------------------------------------------------
path('tag/<slug:slug>/', TagIndexView.as_view(), name='tagged'),
path('like/<int:pk>', LikeView, name='like_post'),
#--------------------------------------------------------------------------------------------------------------------------------------
]
You can use a string literal to specify the model name of a model that still needs to be defined, so you can use ManyToManyField('Category') or ForeignKey('Post', on_delete=models.CASCADE) for example to refer to models not yet defined:
from django.conf import settings
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
location = models.CharField(max_length=100, default="")
tags = TaggableManager()
likes = models.ManyToManyField(settings.AUTH_USER_MODELS, related_name='liked_posts')
categories = models.ManyToManyField('Category')
It however does not seem to make much sense that a Category has a ForeignKey to a post: that would mean that a Category links to exactly one Post record?
You can for example use a ListView with:
class PostListView(ListView):
model = Post
template_name = 'blog/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 199
def get_queryset(self):
qs = super().get_queryset()
if self.request.GET.get('category'):
return qs.filter(categories__name=self.request.GET['category'])
return qs
def get_context_data(self, *args, **kwargs):
context = super().get_queryset(*args, **kwargs)
context['categories'] = Category.objects.all()
return context
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

How to pass multiple values from models.py to HTML via views.py in Django

I have a following models.py for my Django blog, I made a following views.py to pass the value of the slug for my URL parameter.
However I am struggling to create a model in views to get other data(person & description) from Category class.
I have tried some patterns by myself but can not pass them to HTML. (always Error or not showing)
Can you please give me some idea of how to solve this.
models.py
class Category(models.Model):
person = models.CharField(max_length=20)
description = models.TextField()
slug = models.SlugField()
def __str__(self):
return self.person
views.py
def blog_category(request, category):
posts = Post.objects.filter(categories__slug__contains=category).order_by("-created_on").distinct()
context = {"category": category, "posts": posts}
return render(request, "blog_category.html", context)
HTML(Localhost:8000/slug)
{{ person }}
{{ description }}
this is full code of my models.py
class Category(models.Model):
person = models.CharField(max_length=20)
description = models.TextField()
slug = models.SlugField()
def __str__(self):
return self.person
class Recommender(models.Model):
recommender_name = models.CharField(max_length=20)
slug = models.SlugField()
def __str__(self):
return self.recommender_name
class Post(models.Model):
book_title = models.CharField(max_length=255)
author = models.CharField(max_length=255)
book_link = models.CharField(max_length=255)
recommenders = models.ForeignKey("Recommender", on_delete=models.CASCADE,)
source = models.TextField()
source_link = models.CharField(max_length=255)
created_on = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
categories = models.ManyToManyField("Category", related_name="posts")
slug = models.SlugField()
def __str__(self):
return self.book_title
posts = Post.objects.filter(categories__slug__contains=category).order_by("-created_on").distinct()
Is going to return a queryset. It can have more than one instance of the model class (since you are using filter). In your context you are sending this queryset as posts to your templates.
So in your HTML you can use something like this. You need to use a for loop since there can be more than one item in posts.
{% for post in posts %}
{% for category in post.categories.all %}
{{ category.person }}
{{ category.description }}
{% endfor %}
{% endfor %}
I would look at this example.
Namely, if you render the template like it is shown in the example, you should be able to do
{{ category.person }} {{ category.description }}

How can i display a Foreign Key on a select tag in my django template?

I'm trying to display some information on a SELECT tag on my template that passes through a for loop and can't seem to find a how to. The examples I find on the internet aren't dynamics (from another table) and I'm really struggling on that. Bellow are my codes, hope you guys can help me on this.
This is my models.py
class Books(models.Model):
[...]
category_cod_category = models.ForeignKey(
'Category',
on_delete = models.CASCADE
)
class Meta:
db_table = 'Books'
class Category(models.Model):
category_name = models.CharField(
max_length = 45
)
def __str__(self):
return '%s' % self.category_name
class Meta:
db_table = 'Category'
This is my views.py and this bit of code is from another template where I have a button for editing.
def edit(request,id):
book = Books.objects.get(id=id)
return render(request,'edit.html',{'edit_book':book})
This is my template edit.html where i need the category of the books to be displayed. Every other field is OK.
<form method="POST" class="post-form" action="/update/{{ book.id }}">
{% csrf_token %}
[...]
<div class="container">
<label>Categoria do Livro:</label>
<select class="selectpicker form-control" data-live-search="true">
{% for books in Books %}
<option value="{{ edit_livro.category_cod_category}}">{{ edit_livro.category_cod_category}}</option>
{% endfor %}
</select>
<div>
[...]
Can you guys help me? Or send me a place where I can learn how to solve this?
Sorry for any misspellings, I'm not a native english writer.
Thanks!
EDIT:
I'm using ModelForms for my insert template, It's listed below:
class BooksForm(forms.ModelForm):
class Meta:
model = Books
fields = [ ...,'category_cod_category', ... ]
# Step:1
# Create url for views (listing, create, update)
urls.py
path(r'book-listing/', BookListView.as_view(), name='book-info-listing'),
path(r'book-info-create/', BookCreateView.as_view(), name='create-book-info'),
path(r'book-info-edit/<int:id>', BookUpdateView.as_view(), name='edit-book-info'),
# Step:2
# Create form for your model
forms.py
# You just need to set the queryset for your field of form, if you want to get the select tag for all your category
class BooksForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.fields['category_cod_category'].queryset = Category.objects.all()
class Meta:
model = Books
fields = [ ...,'category_cod_category', ... ]
# Step:3
# Create views for your model
views.py
# For Listing a book info
class BookListView(generic.ListView):
model = Books
def get_queryset(self):
books = self.model.objects.all()
return books
# For Creating a new book
class BookCreateView(generic.CreateView):
model = Books
form_class = BookForm
template_name = 'project_app/book-form.html'
def form_valid(self, form):
form.save(self.request)
return redirect('book-info-listing')
# For Editing or updating a book
class BookUpdateView(generic.UpdateView):
model = Books
form_class = BookForm
template_name = 'project_app/book-form.html'
success_url = reverse_lazy('book-info-listing')
# get the object
def get_object(self, *args, **kwargs):
book_info = get_object_or_404(Books, pk=self.kwargs['id'])
return book_info
def form_valid(self, form):
form.save(self.request)
return redirect('book-info-listing')
# Step:4 Render form in your template
book-form.html
<form method="POST" class="books_form">
{% csrf_token %}
{{form.category_cod_category}}
</form>

Two models in one Django DetailView and filtering by relation betwen them

I have a question. In my DetailView I want to placed data from two models. Moreover, I want to filter them, that on my scenario-detail was only that comments related to specyfic scenario, related by ForeignKey->Scenario.
My views.py:
class ScenarioDetailView(LoginRequiredMixin, DetailView):
model = Scenario
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = Comment.objects.all()
return context
And in scenario_detail.html i have a simple {{ comments }}
I thinking on filtering my comment object in views.py, something like: Comment.objects.get(commentScenario=Scenario.id) but it didn't work at all.
My models.py:
class Scenario(models.Model):
scenarioTitle = models.CharField(max_length=256)
scenarioArea = models.ForeignKey(ScenarioArea, on_delete=models.CASCADE)
scenarioAuthor = models.ForeignKey(User, on_delete=models.CASCADE)
scenarioDate = models.DateTimeField(default=timezone.now)
scenarioDescription = models.TextField()
def __str__(self):
return self.scenarioTitle
def get_absolute_url(self):
return reverse('scenario-detail', kwargs={'pk': self.pk})
class Comment(models.Model):
commentText = models.CharField(max_length=256)
commentScenario = models.ForeignKey(Scenario, on_delete=models.CASCADE)
commentAuthor = models.ForeignKey(User, on_delete=models.CASCADE)
commentDate = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.commentText
And urls.py:
path('scenario/<int:pk>/', ScenarioDetailView.as_view(), name='scenario-detail'),
Could someone help me?
You don't need to send any extra context to your template in order to show the related comments; As you already have the related comments to your Scenario with backward relationship.
So you can simply use Scenario.comment_set.all in your template to access them.
As an example:
{% for comment in object.comment_set.all %}
{{ comment }}
{% endfor %}
try this
class ScenarioDetailView(LoginRequiredMixin, DetailView):
model = Scenario
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = Comment.objects.filter(commentScenario=self.object)
return context

Django view with get context not working

Have a quick question. Trying to use a relational model in one DetailView. However, no matter what I try the data does not display. I've tried a few versions of template tags to no avail.
html
{% for parts in relatedparts %}{{ parts.name }}
</div>{% endfor %}
views.py
class ErrorCodeView(DetailView):
context_object_name = 'error_code_details'
model = models.ErrorCodes
template_name = 'error_code_details.html'
def get_context_data(self, **kwargs):
# xxx will be available in the template as the related objects
context = super(ErrorCodeView, self).get_context_data(**kwargs)
context['relatedparts'] = RelatedParts.objects.filter(name=self.get_object())
return context
models.py
class ErrorCodes(models.Model):
name = models.CharField(max_length=256)
description = models.CharField(max_length=400)
instructions = models.CharField(max_length=256)
PartsNeeded = models.CharField(max_length=120, default='')
usercomments = models.CharField(max_length=400, default='', blank=True)
relpic = models.ImageField(upload_to='media/',blank=True)
relpictwo = models.ImageField(upload_to='media/',blank=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("errorcodes:errorcodeview",kwargs={'name':self.name})
class RelatedParts(models.Model):
name = models.CharField(max_length=256)
related_error_code = models.ForeignKey(ErrorCodes, on_delete=models.PROTECT)
def __str__(self):
return self.name
You don't need to do this at all. You can follow the relationship in the template.
{% for part in object.relatedparts_set.all %}{{ part.name }}{% endfor %}
You don't need any code in the view to enable this.
could it be that "name=self.get_object()" should be "name=self.get_object().name" ?
You currently have:
context['relatedparts'] = RelatedParts.objects.filter(name=self.get_object())
but that is probably producing an empty queryset.

Categories

Resources