I have a hierarchy within my Django App. I want to achieve the following:
First show several boards
Then, if the user clicks on one board, I want to display all topics within the board.
Now the problem is that I have declared a foreign key within the Topic model, but now the topic can be called from each of the boards, not only from within the one I assigned it to.
Here my models:
from django.db import models
from django.contrib.auth.models import User
from mptt.models import TreeForeignKey
# overview over all topics
class Board(models.Model):
name = models.CharField(max_length=30, unique=True)
description = models.CharField(max_length=100)
def __str__(self):
return self.name
# topics withing the boards
class Topic(models.Model):
board = TreeForeignKey(Board, on_delete=models.CASCADE, related_name='Topic')
subject = models.CharField(max_length=255, unique=True)
last_updated = models.DateTimeField(auto_now_add=True) # auto_now_add sets current date+time when created
starter = models.ForeignKey(User, on_delete=models.CASCADE, related_name='Topic')
def __str__(self):
return self.subject
Then the views:
from .models import Board, Topic
class BoardsView(generic.ListView):
template_name = 'dbconnect/board.html'
context_object_name = 'board_list'
def get_queryset(self):
""" Return all boards."""
return Board.objects.all()
class TopicView(generic.ListView):
model = Topic
template_name = 'dbconnect/topic.html'
context_object_name = 'topic_list'
def get_queryset(self):
"""Return all topics."""
return Topic.objects.all()
The board.html works fine, since there is no second level in the url:
<div style = "text-align: left; margin-left: 10%; margin-right: 10%">
<div style = "display: inline-block; text-align: left;">
{% if board_list %}
<ul>
{% for board in board_list %}
<li>{{ board.name }}</li>
{% endfor %}
</ul>
{% else %}
<p>No boards are available.</p>
{% endif %}
</div>
But then comes topic.html and now I'm lost, what to pass, so that the topic refers to the board:
<div style = "text-align: left; margin-left: 10%; margin-right: 10%">
<div style = "display: inline-block; text-align: left;">
{% if topic_list %}
<ul>
{% for topic in topic_list %}
<li>{{ topic.subject }}</li>
{% endfor %}
</ul>
{% else %}
<p>No topics are available.</p>
{% endif %}
</div>
Here you can see my urls:
app_name = 'dbconnect'
urlpatterns = [
path('', views.BoardsView.as_view(), name = 'board'),
path('<int:topic>/', views.TopicView.as_view(), name='topic'),
path('<int:topic>/<int:level>/', views.LevelView.as_view(), name='level')]
How could I achieve that to show the restricted topic list inside each board?
The URLs
If I understand your question correctly, you should probably adapt your URLs to fit the case you describe:
urlpatterns = [
...
path('<int:board_id>/', views.TopicView.as_view(), name='topic-list'),
...
]
The first URL can stay the same, but the second URL gets the board_id as URL parameter, not the topic_id, since you want to display a list of topics belonging to the selected board.
And maybe rename that URL from topic to topic-list or something similar to be clearer what it is about.
Now, filtering inside the view:
You can filter your topic queryset like this:
class TopicView(generic.ListView):
model = Topic
...
def get_queryset(self):
return super().get_queryset().filter(board=self.kwargs['board_id'])
You can use super().get_queryset() there as you already defined model = Topic on the class; see the docs.
See this post for a similar case.
Related
I am using MVT in django. I am using generic CBV (listview, detailview). here are my codes
Here is model.py
from django.db import models
class Singers(models.Model):
name= models.CharField(max_length=256)
age= models.IntegerField()
gender= models.CharField(max_length=10)
class Albums(models.Model):
name= models.CharField(max_length=256)
singer=models.ForeignKey(Singers, on_delete=models.CASCADE)
view.py
from django.views import generic
from core.models import Albums, Singers
#in generic view instead of functions, we use classes
class AlbumView(generic.ListView):
model = Albums
template_name = 'index.html'
paginate_by = 10
def get_queryset(self):
return Albums.objects.all()
class DetailView(generic.DetailView):
model = Albums
template_name = 'detailview.html'
Here are urls.py
from django.urls import path
from core.views import AlbumView, DetailView
urlpatterns = [
path('album/', AlbumView.as_view()),
path('album/detail/<pk>/', DetailView.as_view())
]
Here is index.html
{% block content %}
<h2>Albums</h2>
<ul>
{% for albums in object_list %}
<li>{{ albums.name }}</li>
{% endfor %}
</ul>
{% endblock %}
here is detailview.html
{% block content %}
<h1>name: {{Albums.name}}</h1>
<p><strong>Singer: {{Albums.Singer}}</strong></p>
{% endblock %}
The detail view is not working fine. It is not fetching the respective name of the album and singer details.
Suggest me what should i do?
Try this
{% block content %}
<h1>name: {{object.name}}</h1>
<p><strong>Singer: {{object.singer.name}}</strong></p>
{% endblock %}
class DetailView(generic.DetailView):
model = Albums
template_name = 'detailview.html'
This is not working you have to get first context like this
def get_context_data(self, **kwargs):
// Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
// Add in a QuerySet of all the books
context['Album_list'] = Albums.objects.all()
return context
And you can do as well
context_object_name = 'publisher'
queryset = Publisher.objects.all()
Devs,
I have a 2 Models and one of them have a foreign key attribute as a reference to the other. Now I am trying to view both objects in my Template.
class ItemDetailView(DetailView):
model = Item
template_name = "product.html"
def get_context_data(self, **kwargs):
context = super(ItemDetailView, self).get_context_data(**kwargs)
context['markets'] = Market.objects.all()
# And so on for more models
return context
In my template I just want the exact market for my product
I tryed something like this:
{% for market in markets %} // or {% for object.market in markets %}
{% if market.market == object.market %}
>> Do smth if conditions match <<
{% endif %}
{% endfor %}
In the loop I get strings like x1, x2, x3 and object.market have the value x1.
So I just want to output the object for the corresponding market.
But if I check {% if market.market == object.market %} the conditions somehow don't match. When I print them out inside the loop I get x1,x2,x3,... for market.market and x1,x1,x1,... for object.market
These are my models:
class Market(models.Model):
market = models.CharField(max_length=30)
branch = models.CharField(choices=BRANCH_CHOICES, max_length=1)
image = models.ImageField(blank=True)
slug = models.SlugField(blank=True)
def __str__(self):
return self.market
def get_absolute_url(self):
return reverse("core:market-product-list", kwargs={
'slug': self.slug
})
class Item(models.Model):
title = models.CharField(max_length=100)
market = models.ForeignKey(Market, related_name='children', on_delete=models.CASCADE, blank=True, null=True)
price = models.FloatField()
discount_price = models.FloatField(blank=True, null=True)
category = models.ForeignKey(ItemCategory, related_name='children', on_delete=models.CASCADE, blank=True, null=True)
label = models.CharField(choices=LABEL_CHOICES, max_length=1)
slug = models.SlugField()
path = models.CharField(default='/market-product-list/', max_length=100)
description = models.TextField()
image = models.ImageField()
I just solved the issue. The problem was that object.market is interpreted as an object not as a string. So it was impossible to check the conditions in the if-clause. I managed to output the corresponding market with converting the object to a string like this:
At first:
{% if object.market|slugify|capfirst == market.market %}
and then changed it to simply
{% if object.market == market %}
which is obviously the better solution
PS: I also learned that this is bad programming I should not filter in a Template but I am new to Django and I am glad that things are working now :)
Just call the field for the particular market as in the model.
{% for market in markets %} // or {% for object.market in markets %}
{% if market.market == object.market %}
{{ market.fieldname }}
{% endif %}
{% endfor %}
Why don't you loop through Product(Item) objects?
I'm sure this is a very basic question but I have a OneToMany Relationship and I wish to list all the associated children on a page. Here's what i have so far.
Model File
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class Post(models.Model):
title = models.CharField(max_length=100)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse ('blog-post' , kwargs = {'pk': self.pk})
class Paragraph(models.Model):
content = models.TextField(default='')
post = models.ForeignKey(Post,default='', on_delete=models.CASCADE)
def __str__(self):
return self.content
class Subtitle(models.Model):
subtitle = models.CharField(max_length=100,default='')
post = models.ForeignKey(Post,default='', on_delete=models.CASCADE)
def __str__(self):
return self.subtitle
View
model = Post
template_name = 'blog/post.html'
context_object_name = 'post'
HTML FILE
{%block content%}
{% if post.author == user %}
Edit
Delete
{% endif %}
<div class = 'content'>
<h2>{{post.title}}</h2>
<!-- I want to show Subtitle here--><p></p>
<!-- I want to show Paragraph here--><p></p>
<h3>By: {{post.author}} on {{post.date_posted}}</h3>
</div>
{% endblock content %}
Isn't it's just {% for subtitle in post.subtitle_set.all %} {{ subtitle }} {% endfor %} and same for paragraph? – Charnel Feb 23 at 21:42
I have a model D100Generator with an incrementing primary key. I am trying to mimic the Django tutorial pt. 3, substituting a list of table names for the questions that should be rendered on the index.html page. When I run the code, I get a <ul> bullet point, but no text. Is my latest_table_list not being populated? Or is it I'm calling the wrong thing?
I am very new to Python, web development and Stack Overflow, so forgive me if the formatting and explanation is poor on this.
I suspect I'm not calling the table_name field correctly, but nothing I've tried has been able to work.
I tried setting the line item for the list as:
<li>{{ d100Generator.table_name }}</li>
and as:
<li>{{ d100Generator.table_name }}</li>
Neither of which will help display as desired.
The D100Generator Model
class D100Generator(models.Model):
d_100_id = models.AutoField(primary_key=True)
field_of_interest = models.ForeignKey(FieldOfInterest, on_delete=models.CASCADE)
subreddit_post_id = models.ForeignKey(Subreddit, on_delete=models.CASCADE, blank=True, null=True)
module_id = models.ForeignKey(Module, on_delete=models.CASCADE, blank=True, null=True)
generic_website_id = models.ForeignKey(GenericWebsite, on_delete=models.CASCADE, blank=True, null=True)
table_name = models.CharField('table name', max_length=100)
system = models.CharField(max_length=150)
genre = models.CharField(max_length=250)
chart_type = models.CharField('Die used', max_length=15)
chart_instructions = models.TextField('Chart instructions & explanation')
roll_1 = models.TextField('1', blank=True, null=True)
roll_2 = models.TextField('2', blank=True, null=True)
roll_3 = models.TextField('3', blank=True, null=True)
...
roll_110 = models.TextField('110', blank=True, null=True)
def __str__(self):
return self.table_name
#Views.py Entry for Index
from django.shortcuts import render
from .models import D100Generator
def index(request):
latest_table_list = D100Generator.objects.order_by('-d_100_id')[:5]
context = {
'latest_table_list': latest_table_list
}
return render(request, 'generators/index.html', context)
##Code on the index.html page itself
<h1>Welcome to Capstone Generators' homepage!</h1>
<br>
<h2>Recent topics added include:</h2>
<br>
<h2>Recent tables added include:</h2>
{% if latest_table_list %}
<ul>
{% for d_100_id in latest_table_list %}
<li>{{ D100Generator.table_name }}</li>
{% endfor %}
</ul>
{% else %}
<p>No tables are available.</p>
{% endif %}
I have one table the has been manually added via the admin page, so the bulleted list should include the table name "Your elf learned over 25 years..."
Here you are using loop variable d_100_id but you are trying to access table_name with D100Generator
So change this to:
{% for d_100_id in latest_table_list %}
<li>{{ d_100_id.table_name }}</li>
{% endfor %}
I am having a hard time figuring out the right logic for my problem, i have 3 models,
class Item(SmartModel):
name= models.CharField(max_length=64,help_text="Name for this item e.g Hamburger")
price=models.DecimalField(max_digits=9,decimal_places=2)
optionalitems = models.ManyToManyField('optionalitems.OptionalItemCategory',null=True,blank=True)
class OptionalItems(SmartModel):
"""Optional items that belong to an item e.g topping that belongs to a pizza"""
name = models.CharField(max_length=20, help_text="Item name.")
price = models.DecimalField(max_digits=9, decimal_places=2, null=True,blank=True)
class OptionalItemCategory(SmartModel):
"""Category to which optional items belong"""
title = models.CharField(max_length=20,help_text="Category name")
optional_items = models.ManyToManyField(OptionalItems)
in my template,
{%for optionalcategory in optionalcategories %}
<h5 id="blah"> {{ optionalcategory.title}} </h5>
{% for optionalitem in optionalcategory.optional_items.all %}
<ul>
<input type="radio" value="radio" name="optional" value="op"><li id="item_appearence">{{optionalitem.name}}<span> {{optionalitem.price}}</span></li><a/>
</ul>
{% endfor %}
{% endfor %}
So for example an Item like a burrito will have an OptionalItem steak or chicken.I am able to access the Item like so item = get_object_or_404(Item, pk=obj.id) but my problem is i cannot figure out how to capture the OptionalItem. I want to be able to access the OptionalItem, i want to obtain the value of the radio button and its attributes. its kind of tricky.
Your code is inconsistent and that makes it hard to read, understand and work with. Some advice, clean it up. Something like this:
class Category(models.Model):
name = models.CharField(max_length=200)
class Option(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True)
class Item(models.Model):
category = models.ForeignKey(Category)
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True)
options = models.ManyToManyField(Option)
Than you need a from and a view. As I interpret your question: you want a form to select a option for an Item. So the code below will render all options and the widget RadioSelect() lets the user select one item. But why use radiobuttons? If an Item has a relation to one Option, than the Item model should have a foreignKey not M2M!
Form:
class ItemForm(ModelForm):
options = forms.ChoiceField(widget=forms.RadioSelect())
class Meta:
model = Item
fields = ( 'options', )
View:
from django.shortcuts import render
from django.http import HttpResponseRedirect
def your_view(request, id):
item = Item.objects.get(pk=id) # Your item object.
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
options = form.cleaned_data['options']
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ArticleForm(instance=article)
return render(request, 'contact.html', {
'form': form,
})
Template:
{% for obj in item.options_set.all %}
{{ obj.name }} {{ obj.price }}
{% endfor %}
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
I dind't test the code. But this should get you started. The documentation is your friend:
https://docs.djangoproject.com/en/1.5/topics/forms/
https://docs.djangoproject.com/en/1.5/#forms
In your template, you can simply render the price. I'd write a method in the Item model, that formats the OptionalItems the way you like.
i.e.
class Item(SmartModel)
...
def get_optional(self):
return ','.join([a.optionalitems for a in self.optionalitems.all()])
Of course, you should change that method to have it format the way you'd like.
If you pass a queryset of Items to your template, you can do something like the following:
{% for item in items %}
Name: {{ item.name}}
Price: {{ item.price }}
Optional Items: {{ item.get_optional }}
{% endfor %}