Reversing a url with two slugs - python

I am trying to understand a basic example of adding both categories and detail slugs from 2 related classes.
The /categories URL works, but I can't make /categories/detail work. I get the following error:
Reverse for 'categorydetail' with arguments '('onedetailfromcategory',)' not found. 1 pattern(s) tried: ['(?P<cat_slug>[^/]+)/(?P<det_slug>[^/]+)$']
Here are my files:
#Models:
class Categories(models.Model):
name = models.CharField(max_length=50,unique=True)
cat_slug = models.SlugField(max_length=100,unique=True)
def __str__(self):
return self.name
class Details(models.Model):
title = models.CharField(max_length=100)
det_slug= models.SlugField(max_length=100,unique=True)
categorie = models.ForeignKey('Categories', on_delete=models.CASCADE, related_name="Categories")
def __str__(self):
return self.title
#Views:
class ListCategorie(DetailView):
model = Categories
slug_field = 'cat_slug'
context_object_name = "listcategories"
template_name = "show/categories.html"
class DetailCategorie(DetailView):
model = Details
slug_field = 'det_slug'
context_object_name = "categorydetail"
template_name = "show/detail.html"
#Urls:
path('<cat_slug>', views.ListCategorie.as_view(), name='listcategories'),
path('<cat_slug>/<det_slug>', views.DetailCategorie.as_view(), name='categorydetail'),
#Categories.html
{% for x in listcategories.Categories.all %}
<p> {{x.title}} </p>
<li>URL</li>
{% endfor %}

Your URL pattern is
path('<cat_slug>/<det_slug>', views.DetailCategorie.as_view(), name='categorydetail'),
Therefore you need to provide cat_slug and det_slug when reversing the URL:
{% url 'categorydetail' x.categorie.cat_slug x.det_slug %}

Related

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 }}

Update button not getting the query

thanks for your time:
I've got a model that is linked to the user and the only one that can update him its his creator. untill that works fine. just the creator user can open the url update although i'm not beeing able to pass a button on the main template of the model with redirect to that update url.
i'd like to know if there is a way to that button apear just to his user (if not ok, to get in just open to the matching queryset user).
Or just why this button ain't working: i should get the url eg:services/parceiro/update/2 i'm beeing able to open this url if i'm the creator user but when i try to set it in a button i get this error:
Reverse for 'update_parceiro2' with arguments '('',)' not found. 1 pattern(s) tried: ['services/parceiro/update/(?P[0-9]+)$']
parceiros.html:
{% extends "base.html" %}
{% block content %}
<h1>{{parc.nome}} - {{parc.user}} - {{parc.responsavel}}</h1>
<form action="{% url 'update_parceiro2' Parceiros.id %}">
<button type="submit"><i class="material-icons">sync</i></button>
</form>
{% endblock %}
views.py:
def parceirosview(request, pk=None):
parc = get_object_or_404(Parceiros, id=pk)
context = {'parc': parc}
return render(request, 'parceiro.html', context)
def get_queryset(self):
return super().get_queryset().filter(parceiro__user=self.request.user)
class ParceiroUpdate(UpdateView):
model = Parceiros
template_name = 'parceiroform.html'
fields = ['nome', 'endereco', 'responsavel', 'tel']
def get_queryset(self):
return super().get_queryset().filter(user=self.request.user)
urls.py:
urlpatterns = [
path('home/', views.home_view, name='home2'),
path('parceiro/', views.parceirosview, name='parceiro2'),
path('parceiro/detail/<int:pk>', views.parceirosview, name='parceiro_detail2'),
path('addparceiro/', views.parceiros_create, name='add_parceiro2'),
path('parceiro/detail2/<int:pk>', ParceirosView.as_view(), name='parceiro_detail22'),
path('parceiro/update/<int:pk>', ParceiroUpdate.as_view(), name='update_parceiro2')
]
models.py:
get_user_model = User
class Parceiros (models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
nome = models.CharField(max_length=200)
endereco = models.TextField(max_length=400, blank=True)
responsavel = models.CharField(max_length=100)
tel = PhoneField(max_length=12)
created_at = models.DateTimeField(auto_now=True)
updated_at = models.DateTimeField(auto_now_add=True, blank=True)
ativo = models.BooleanField(default=False)
def get_queryset(self):
queryset = super(Parceiros, self).get_queryset()
return queryset
def __str__(self):
return '%s %s' % (self.user, self.nome)
def get_absolute_url(self):
return reverse('parceiro_detail2', kwargs={'pk': self.pk})
You can use this code in your template to display content for user based on his id
{% if request.user.id == 1 %}
<form action="{% url 'update_parceiro2' Parceiros.id %}">
<button type="submit"><i class="material-icons">sync</i></button>
</form>
{% endif %}

Django If in the article, show all the article titles in the category of this article

Hello i need a little help.
I create django cms.
I cant filter category in my post page.
I want, If I'm in the post page, I would like to see other post titles in this category.
Let me explain;
i have three post. post title is like this;
1-bmw3series
2-bmw5series
3-teslaroadster
1st and 2nd post in "bmw" category
3nd post in the "tesla" category
I want to show post categories in the left area. but I want to show post title of that post categorie.
For example, if I'm in bmw5series page, I want only see left category area to bmw3series and bmw5series post titles.
When I use the following code
{% for category in category %}
{% for article in category.get_article %}
<li><a title="{{ article.title }}" href="{% url 'article:detail' slug=article.slug %}">{{ article.title }}</a></li>
{% endfor %}
{% endfor %}
All post titles are listed... so if im inside bmw5series post just I need to see articles in bmw category....
How do I filter them?
views.py
from django.shortcuts import render, get_object_or_404
from .models import Article, Category
def index(request):
articles = Article.objects.all()
category = Category.objects.all()
context = {
"articles": articles,
"category": category,
}
return render(request, 'index.html', context)
def detail(request,slug):
article = get_object_or_404(Article, slug = slug)
category = Category.objects.all()
return render(request, "detail.html", {"article":article, "category":category,})
def category_detail(request,slug):
template = "category_detail.html"
category=get_object_or_404(Category,slug=slug)
article=Article.objects.filter(category=category)
context = {
'article' : article,
}
return render(request,template,context)
models.py
class Category(models.Model):
name = models.CharField(max_length=120, verbose_name="name")
parent = models.ForeignKey('self',blank=True, on_delete = models.CASCADE, null=True ,related_name='children')
slug = models.SlugField(unique=True, max_length=130)
def __str__(self):
return self.name
def get_article(self):
return Article.objects.filter(category=self)
class Article(models.Model):
author = models.ForeignKey("auth.User",on_delete = models.CASCADE, verbose_name="Yazar")
title = models.CharField(max_length = 120, verbose_name="Başlık")
category = models.ForeignKey('Category', on_delete=models.CASCADE, null=True, blank=True)
content = RichTextField(verbose_name="İçerik")
created_date = models.DateTimeField(auto_now_add=True, verbose_name="Oluşturma Tarihi")
image = models.ImageField(blank=True, null=True, verbose_name="Foto Ekle (.jpg .png)")
slug = models.SlugField(unique=True, max_length = 130)
def __str__(self):
return self.title
def get_unique_slug(self):
slug = slugify(self.title.replace("ı","i"))
unique_slug = slug
counter = 1
while Article.objects.filter(slug=unique_slug).exists():
unique_slug = '{}-{}'.format(slug, counter)
counter += 1
return unique_slug
def save(self, *args, **kwargs):
if not self.slug:
self.slug = self.get_unique_slug()
return super(Article, self).save(*args, **kwargs)
Try renaming this
{% for category in category %}
{% for article in category.get_article %}
To this
{% for cat in category %}
{% for article in cat.get_article %}
UPDATE
If I understand you correctly, whenever you display an article, you want to display the articles of that article's category. If that is correct then you have to change
category = Category.objects.all()
to
category = Category.objects.filter(article=article)

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.

Building cascade structure

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

Categories

Resources