Django get abstract model value in template - python

I have abstract models and it displays when item created. How can i get this variable and display in my template?
class BaseModel(models.Model):
class Meta:
abstract = True
_created = models.DateTimeField(auto_now_add=True)
class Toy(BaseModel):
name = models.CharField(max_length=250)
views.py
toys = Toy.objects.all()
index.html
{% for k in toys %}
{{k.created}}
{% endfor %}
I tried this one but it doesn't work.

It's not ideal, but if you only need the _created field, create an empty list in your view, and then populate it with the field for each instance. Then, return the new list as a context variable.
For example,
created_values = []
for value in Toy.objects.all():
created_values.append(value._created)
The above is not tested, but I believe it should work.

Related

Query two models in Django into one queryset

I have two models in my django app:
class Person(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
persons = models.ManyToManyField(Person, related_name="books")
Now I need to create a view that will make one query for regex to both of the models, find the ones that are matching and display them in template.
If I do:
class SearchListView(ListView):
queryset = Person.objects.filter(name__icontains="a")
book_queryset = Book.objects.filter(title__icontains="a")
I get an error that ListView accepts only one queryset.
What is the typical solution to such problem?
You need to do something a little bit different here:
class SearchListView(ListView):
queryset = Person.objects.filter(name__icontains="a")
def get_context_data(self, **kwargs):
context = super(SearchListView, self).get_context_data(**kwargs)
context['book_queryset'] = Book.objects.filter(title__icontains="a")
return context
Then in your view you can do somenting like the following:
{% for object in object_list %}
<p>{{object}}</p>
{% endfor %}
{% for object in book_queryset %}
<p>{{object}}</p>
{% endfor %}
The reason why the way you are using is not working is because ListView inherit from MultipleObjectMixin the queryset property and that property is passed to object_list context variable in the template, that happens under the hood and if you want to pass more context variables to the template you need to follow the approach I shared.

Django: How to autopopulate foreign key with the corresponding model class instance

Working on my first Django project and could use some help. I have 2 models (Decisions, Votes) linked by the foreign key called 'decision'. The template, vote_list.html, shows the user a list of decisions (generated by other users) that are contained in Decisions. The user taps a particular decision and is re-directed to a second template to vote on options pertaining to that decision. How do I autopopulate the foreign key 'decision' in Votes with the corresponding instance of Decision so that the second template, vote_form.html, displays the options for the decision they tapped on? I assume it's coded in views.py (I commented an attempt below that doesn't work), but how might it be done? Thank you!
urls.py
path('vote-list/', views.VoterView.as_view(), name='vote_list'),
path('vote-list/<pk>/vote-form/', views.VoteForm.as_view(), name='vote_form'),
models.py
class Decisions(models.Model):
custom_user = models.ForeignKey(CustomUser,
default=None, null=True,
on_delete=models.SET_NULL)
description = models.CharField(default="",
max_length=100, verbose_name="Decision
Summary")
class Votes(models.Model):
decision = models.ForeignKey(Decisions,
default=None, null=True,
on_delete=models.SET_NULL)
vote = models.CharField(default="", max_length=100,
verbose_name="Your vote")
views.py
class VoteForm(LoginRequiredMixin, CreateView):
model = Votes
form_class = VotingForm
template_name = 'users/vote_form.html'
def post(self, request, *args, **kwargs):
super()
form = self.form_class(data=request.POST)
if form.is_valid():
instance = form.save(commit=False)
# instance.decision = Decisions.description
instance.save()
return redirect('users:vote_list')
forms.py
class VotingForm(forms.ModelForm):
class Meta:
model = Votes
fields = ['vote']
vote_list.html
{% for item in Decisions %}
<tr>
<td>{{ item.description }}</td>
<td><a href="{% url 'users:vote_form' item.id
%}">Vote</a></td>
</tr>
{% endfor %}
vote_form.html
{# trying to display the corresponding
decision description here from vote_list.html # }}
{{ form.vote|as_crispy_field }}
I think this might solve your problem:
Add decision field in the voting form. This will display an option to select for which decision you need to save this Vote for.
If you don't want to allow users to change the Decision, you can mark the field as disabled. See this issue for more details on how to do that. Another alternative is to completely hide the field.
class VotingForm(forms.ModelForm):
class Meta:
model = Votes
fields = ['vote', 'decision']
Add initial value of the decision when instantiating the VotingForm. This will automatically set which decision is selected when displaying the form.
class VoteForm(LoginRequiredMixin, CreateView):
model = Votes
form_class = VotingForm
template_name = 'users/vote_form.html'
# Use this to pass 'pk' to your context in the template
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({'pk': self.kwargs['pk'})
return context
def get_initial(self):
initial = super().get_initial()
initial.update({'decision': self.kwargs['pk']})
return initial
def get_success_url():
# Import reverse from django.urls
return reverse('users:vote_list')
Also, your form should probably be displayed like this in the HTML template: {% crispy form %}. This way all defined fields from the VotingForm class are rendered automatically.
<form method="post" action="{% url 'users:vote_form' pk %}">
{% crispy form %}
</form>

Django - Accessing Model Field in class based view

I have this model
class Post(models.Model):
title = models.CharField(max_length=100)
title2 = models.CharField( max_length=100)
content = models.TextField(default=timezone.now)
content2 = models.TextField(default=timezone.now)
post_image = models.ImageField(upload_to='post_pics')
post_image2 = models.ImageField(upload_to='post2_pics')
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
and this function based view that uses the model:
class PostListView(ListView):
model = Post
template_name = 'front/front.html'
context_object_name = 'listings'
ordering = ['-date_posted']
def get_context_data(self, **kwargs):
check_for_zipcode = #where I want to access the author for the current instance
context = super().get_context_data(**kwargs)
context['zipcodes'] = check_for_zipcode
return context
All I want to know is how can I access the author field in the class-based view. I can access the author in my HTML like so"
{% for listings in listings %}
<h3>listings.author</h3>
{% endfor %}
With this, I'll get back the author field for every instance of that model.
How would I get the author for the instance in the variable check_for_zipcode? I tried self.author, self.listings.author, etc; but nothing works
In get_context_data method you have the object_list which is the result of get_queryset method. So you can override the get_queryset method. You can even do the same in get_context_data in object_list. Sample example as below:
def get_queryset(self):
return Post.objects.all().annotate(zipcode=F('author'))
Then in your template:
{% for listing in listings %}
<h3>listing.zipcode</h3>
{% endfor %}
This returns the id of author object since it is a foreignkey. If you want some other attribute like username then do author__username in the annotate function.

Django: How to iterate over two one-two-many table relationships?

I am trying to build a simple web page that queries three tables. There is a Company table that has a one-to-many relationship with a Position table, as well as a one-to-many relationship with a Project table.
The goal is to have the page display a given company once, along with all positions and and projects associated with said company. Then, move on to display the next company, any positions held there and projects completed.
Below is the closest I've come to getting this right. But, the obvious problem is that if there is more than one project associated with a given company, you'll see that company listed more than once.
I'm new to Django, so in the interest of learning, I wanted to beat my own head sufficiently hard before asking for help; but I could really use some fresh ideas at this point.
Also: I can see how a nested for loop might work here, but I'm just not clear on how the mechanics of that would work with the query, and then within the template.
Models:
from django.db import models
class Company(models.Model):
company_id = models.AutoField(primary_key=True)
company_name = models.CharField(max_length=20)
company_logo = models.ImageField(upload_to='images/')
def __str__(self):
return self.company_name
class Position(models.Model):
position_id = models.AutoField(primary_key=True)
position_title = models.CharField(max_length=55)
company_id = models.ForeignKey('professional.Company',
on_delete=models.CASCADE,
blank=True,
null=True)
begin_date = models.DateField()
end_date = models.DateField()
def __str__(self):
return self.position_title
class Project(models.Model):
project_id = models.AutoField(primary_key=True)
project_name = models.CharField(max_length=55)
company_id = models.ForeignKey('professional.Company',
on_delete=models.CASCADE,
blank=True,
null=True)
project_description = models.CharField(max_length=500)
project_image = models.ImageField(upload_to='images/')
def __str__(self):
return self.project_name
View:
from django.views.generic import TemplateView, ListView
from professional.models import Company
class ProfessionalHome(TemplateView):
template_name = 'professional/professional_home.html'
class TechnologyListView(ListView):
template_name = 'professional/__technology.html'
context_object_name = 'technology_list'
def get_queryset(self):
return Company.objects.values('company_name','position__position_title', 'project__project_name')
HTML and template:
{% for job in technology_list %}
<h1>{{job.company_name}}</h1>
<h1>Position: {{job.position__position_title}}</h1>
<h1>project: {{job.project__project_name}}</h1>
{% endfor %}
Instead of values in get_queryset method, you can return the actual queryset and then iterate over it to build your view.
def get_queryset(self):
return Company.objects.all()
Then in your template:
{% for job in technology_list %}
<h1>{{job.company_name}}</h1>
{% for position in job.position_set.all() %}
<h1>Position: {{position.position_title}}</h1>
{% endfor %}
{% for project in job.position_set.all() %}
<h1>project: {{project.project_name}}</h1>
{% endfor %}
{% endfor %}
If you want to iterate over companies, then you should use the Company model as the basis for your view, not Technology. Also, you should avoid values and values_list unless you know you have a good reason, which you don't here. You can use prefetch_related() to reduce the number of reverse queries. So:
class TechnologyListView(ListView):
def get_queryset(self):
return Company.objects.all.prefetch_related('project','position')
...
{% for company in company_list %}
<h1>{{company.company_name}}</h1>
{% for position in company.position_set.all %}
<h1>Position: {{ position.position_title }}</h1>
{% endfor %}
{% for project in company.project_set.all %}
<h1>project: {{ project.project_name }}</h1>
{% endfor %}
{% endfor %}
(Note, you should avoid giving your ForeignKey fields names ending in "_id". The Django field refers to the entire Company, not the ID; the fields should be called just company. The underlying database will be suffixed with _id anyway. Also, you don't need to use model_name prefixes on all your fields; it will be obvious from the object they are accessed on.)

render django tag inside textfield written in html

im a beginner in django and general programming and would like to ask a questions regarding how to render django model field in html save inside textfield.
my code snippet as per below:
models.py
class Recipe(models.Model):
recipe_name = models.CharField(max_length=128)
recipe_text = models.TextField()
ingredients = models.TextField()
def __str__(self):
return self.recipe_name
I have ingredient model which contains object for ingredients for example sugar or salt.
class ingredient(models.Model):
ingredient_name = models.CharField(max_length=200)
ingredient_text = models.TextField()
def __str__(self):
return self.ingredient_name
For example if i create salt ingredient object with the ingredient_name of 'salt', i want to call the ingredient_name inside instantiated Recipe object, ingredients field using the ul list html code save inside it using form and pass the code to the template using autoescape or safe tag. but it doesnt seem to work for the field.
The html work for ul list, but the content doesnt seems to work . it will only load for example a string of {{ ingredients.0.ingredient_name }}
i pass both the recipe objects and ingredient objects in views.py
is there any other way to do this?
You need to link Recipe to Ingredients:
class Ingredient(models.Model):
ingredient_name = models.CharField(max_length=200)
ingredient_text = models.TextField()
def __str__(self):
return self.ingredient_name
class Recipe(models.Model):
recipe_name = models.CharField(max_length=128)
recipe_text = models.TextField()
ingredients = models.ManytoMany(Ingredient)
def __str__(self):
return self.recipe_name
Then, create your ingredient, like this:
salt = Ingredient(ingredient_name='salt', ingredient_text='as per taste')
salt.save()
chips = Ingredient()
chips.ingredient_name = 'Chips'
chips.ingredient_text = 'Delicious, goes well with salt'
chips.save()
Next, add it to a recipe:
recipe = Recipe()
recipe.recipe_name = 'Salty Chips'
recipe.recipe_text = 'Great for parties'
recipe.save() # You have to save it first
recipe.ingredients_set.add(salt)
recipe.ingredients_set.add(chips)
recipe.save() # Save it again
Now, in your view:
def show_recipe(request):
recipes = Recipe.objects.all()
return render(request, 'recipe.html', {'recipes': recipes})
Finally, in your template:
{% for recipe in recipes %}
{{ recipe.recipe_name }}
<hr />
Ingredients:
<ul>
{% for ingredient in recipe.ingredients_set.all %}
<li>{{ ingredient }}</li>
{% endfor %}
</ul>
{% endfor %}
This works because you have created a relationship between your Recipe and Ingredient model in such a way that each Recipe can have one or more Ingredient objects linked to it.
Django will keep track of the relations for you, and using the model api you can add (and remove) ingredients to any recipe object.
Since the relations are managed for you, whenever you have a Recipe object, it knows all the Ingredient objects that are linked to it; and we can easily print the correct recipe.

Categories