I would like to get the total amount of followers attached to the models using in models :
class Project(models.Model):
owner = models.ForeignKey(User, related_name='project_created_by', on_delete=models.CASCADE)
name = models.CharField(max_length=100)
description = models.TextField(max_length=150, blank=True, null=True)
followers = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='followers', blank=True)
created = models.DateTimeField(auto_now_add=True)
last_modefied = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
Here is the class
class ProjectListView(ListView):
template_name = 'projectmanagement/project.html'
context_object_name = 'projects'
def get_queryset(self):
queryset = Project.objects.filter(owner=self.request.user).order_by("name")
return queryset
def get_context_data(self, *args, **kwargs):
context = super(ProjectListView, self).get_context_data(*args, **kwargs)
project = Project.objects.get(pk=12) <-- HERE -->
context['followers'] = project.followers.filter(followers=project).count()
return context
You can .annotate(..) [Django-doc] the queryset of your Product with the number of followers:
from django.db.models import Count
class ProjectListView(ListView):
model = Project
template_name = 'projectmanagement/project.html'
context_object_name = 'projects'
def get_queryset(self):
return super().get_queryset().annotate(
nfollowers=Count('followers')
).filter(
owner=self.request.user
).order_by('name')
Now all projects in the context data will have an extra attribute nfollowers with the number of followers.
You can thus render this for example with:
{% for project in projects %}
{{ project.name }}, followers: {{ project.nfollowers }}<br>
{% endfor %}
Related
I have two models: a Project model and ProjectNotes. ProjectNotes are notes that are related to Projects. The ProjectNotes model has a project field that is a foreign key of the related Project.
The problem I have is that when I delete a note on a project, the entire project is deleted. Only the note should be deleted. I think I have on_delete=models.cascade set up correctly on the ProjectNotes model. So I think the issue is with the view.
The models:
class ProjectManager(models.Manager):
def search(self, query=None):
qs = self.get_queryset()
if query is not None:
or_lookup = (
Q(title__icontains=query) |
Q(description__icontains=query)
# Q(slug__icontains=query)
)
qs = qs.filter(or_lookup).distinct() # distinct() is often necessary with Q lookups
return qs
def get_with_counted_notes_documents_todos(self):
queryset = self.get_queryset().annotate(
num_notes=Count('notes'),
num_documents=Count('project_documents'),
num_todos=Count('todo_group')
)
return queryset
class Project(models.Model):
title = models.CharField(max_length= 200)
description = tinymce_models.HTMLField()
status = models.CharField(max_length=20, choices=PROJECT_CHOICES, default="active")
date = models.DateTimeField(auto_now_add=True, null=True)
created_by = models.ForeignKey(CustomUser, editable=False, null=True, blank=True, on_delete=models.RESTRICT)
tags = tagulous.models.TagField(to=SiteWideTags, blank=True, related_name='projects_tags')
objects = ProjectManager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('company_project:project_detail', args=[str(self.id)])
class ProjectNotesManager(models.Manager):
def search(self, query=None):
qs = self.get_queryset()
if query is not None:
or_lookup = (
Q(title__icontains=query) |
Q(body__icontains=query)
# Q(slug__icontains=query)
)
qs = qs.filter(or_lookup).distinct() # distinct() is often necessary with Q lookups
return qs
class ProjectNotes(models.Model):
title = models.CharField(max_length=200)
body = tinymce_models.HTMLField()
project = models.ForeignKey(Project, default=0, blank=True, on_delete=models.CASCADE, related_name='notes')
date = models.DateTimeField(auto_now_add=True, null=True)
created_by = models.ForeignKey(CustomUser, editable=False, null=True, blank=True, on_delete=models.RESTRICT)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('company_project:project_note_detail', args=[self.project_id, str(self.id)])
objects = ProjectNotesManager()
The view:
class ProjectNoteDeleteView(DeleteBreadcrumbMixin, DeleteView):
model = ProjectNotes
template_name = 'company_accounts/delete_project_note.html'
#cached_property
def crumbs(self):
project = self.get_object()
relate_notes = self.get_note()
bread_crumbs = [
("projects", reverse(
"company_project:" + CompanyProjects.list_view_name, )
),
(f"{project.title}",
reverse(
"company_project:" + CompanyProjectsDetailView.detail_view_name,
kwargs={'pk': project.id})
),
("notes", reverse(
"company_project:projectnotes_list",
kwargs={'pk': project.id})
),
(f"{relate_notes.title}",
reverse(
"company_project:project_note_detail",
kwargs={'project_pk': project.id, 'pk': self.kwargs.get('pk')})
),
(f"Delete: {relate_notes.title}",
reverse(
"company_project:project_note_detail",
kwargs={'project_pk': project.id, 'pk': self.kwargs.get('pk')})
)
]
return bread_crumbs
def get_object(self):
return get_object_or_404(Project, id=self.kwargs.get('project_pk'))
def get_note(self):
project = self.get_object()
return get_object_or_404(project.notes, id=self.kwargs.get('pk'))
def related_project(self, **kwargs):
project = get_object_or_404(Project, id=self.kwargs.get('project_pk'))
return project
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
context["note"] = self.get_note()
context['project'] = self.get_object()
return context
def get_success_url(self):
return reverse('company_project:project_detail', args=[(self.object.id)])
The URL:
path('project/<int:project_pk>/note/<int:pk>/delete', ProjectNoteDeleteView.as_view(), name='project_note_delete'),
The template:
<!-- templates/company_accounts/delete_project_note.html -->
{% extends 'base.html' %}
{% block content %}
<div class="section-container container">
<div class="general-main-column">
<div class="row">
<form method="post">{% csrf_token %}
<p>Are you sure you want to permanently delete project note "{{ note }}"?</p>
<input type="submit" class="btn btn-danger" value="Confirm">
</form>
</div>
</div>
</div>
{% endblock content %}
Look at the DeleteView implementation here.
As we can see DeleteView calls delete method for the result of calling get_object function, but your implementation of get_object return instance of Project model:
def get_object(self):
return get_object_or_404(Project, id=self.kwargs.get('project_pk'))
so this is a reason why your project deletes after you try to delete project note.
I want to render every {{ episode.object }} in single video.html page where it works fine for {{ video.object }}. But it isn't showing anything for episode object.. The final template video.html that I want to render episode objects can be seen here https://ibb.co/K9NMXtS
I tried
{% for episode in episodes %}
{{ episode.title }}
{% endfor %}
But that didn't worked. Here is the other configurations:-
#models.py
class Video(models.Model):
title = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=200, unique=True)
year = models.CharField(max_length=4)
category = models.CharField(max_length=3)
trailer = models.URLField(default='')
def __str__(self):
return self.title
def get_absolute_url(self):
from django.urls import reverse
return reverse("video.html", kwargs={"slug": str(self.slug)})
class Episode(models.Model):
video = models.ForeignKey(Video, related_name='episodes', on_delete=models.CASCADE)
title = models.CharField(max_length=512)
air_date = models.DateField()
videolink = models.URLField(default='')
def __str__(self):
return self.title
# urls.py
urlpatterns = [
path('video/<slug>/', views.VideoDetail.as_view(), name='videos'),
]
# view.py
class VideoDetail(DetailView):
model = Video
template_name = 'video/video.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args,**kwargs)
context['Episodes'] = Episode.objects.all()
return context
Python and Django templates are case sensitive. You use Episodes in the view, which doesn't match episodes in the template. Change one of them so that it matches (episodes is recommended for model instances in Python/Django).
Next, you are using Episode.objects.all() at the moment, which will display all episodes. If you only want the episodes for that video, then filter the queryset:
context['episodes'] = Episode.objects.filter(video=self.object)
Or you can get the same result by following the foreign key backwards:
context['episodes'] = self.object.episodes.all()
add VideoDetail, self in super tag
and while calling in template {{ episode.video.slug }}
and slug enough in url
path('video/<slug>/', views.VideoDetail.as_view(), name='videos'),
class VideoDetail(DetailView):
model = Episode
template_name = 'video/video.html'
def get_context_data(self, *args, **kwargs):
context = super(VideoDetail, self).get_context_data(*args,**kwargs)
context['Episodes'] = Episode.objects.all()
return context
I have a list of countries, they all have there own url www.example.com/al/ for example. There is a list of cities for every country but the object_list is empty
My View:
class CityOverview(generic.ListView):
template_name = 'shisha/pages/country_index.html'
model = City
def get_queryset(self, *args, **kwargs):
country_id = self.kwargs.get('country_id')
return City.objects.filter(country__name=country_id)
My Model:
class Country(models.Model):
COUNTRY_CHOICES = (
('al', 'Albania'),
('ad', 'Andorra'),
#etc. etc.
)
name = models.CharField(max_length=255, choices=COUNTRY_CHOICES, default='nl')
def __str__(self):
return self.name
class City(models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE)
name = models.CharField(max_length=250)
def __str__(self):
return self.name
My Urls:
path('<str:country_id>', views.CityOverview.as_view(), name='country'),
My Template:
{{ object_list }}
It returns an empty QuerySet
<QuerySet []>
Does anyone know what the problem is?
The problem is you are trying to match country__name to country_id. Alter the last line in get_queryset to become return City.objects.filter(country__id=country_id) which will now filter the country_id supplied against City's country id.
May be your returning query is wrong,
class Country(Models.model):
country_id=Autofield()
country_name=CharaField()
in Views.py
def get_queryset(self, *args, **kwargs):
country_id = self.kwargs.get('country_id')
return City.objects.filter(country_id=country_id)
I try to create changing button after user join to Goal.
I have work buttons, but i don't know how to change this in template.
I try to do this with boolean field, when user click "Join", boolean field change to True, and then in template I try:
{% if goal.joined %}
<Delete join>
{% else %}
<join to goal>
{% endif %}
Models:
class Goal(models.Model, Activity):
title = models.CharField(max_length=255, verbose_name='Tytuł')
image = models.ImageField(upload_to='goals', verbose_name='Tło')
body = HTMLField(verbose_name='Treść')
tags = TaggableManager()
created_at = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
slug = AutoSlugField(populate_from='title')
def __str__(self):
return self.title
class Meta:
verbose_name = 'Cele'
ordering = ['-created_at']
def get_absolute_url(self):
return reverse('goaldetail', args=[str(self.slug)])
#property
def activity_actor_attr(self):
return self.author
def add_user_to_list_of_attendees(self, user):
registration = Joined.objects.create(user = user,
goal = self,
created_at = timezone.now())
def remove_user_from_list_of_attendees(self, user):
registration = Joined.objects.get(user = user, goal = self)
registration.delete()
class Joined(models.Model, Activity):
goal = models.ForeignKey(Goal, on_delete=models.CASCADE, related_name='joined')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='joined_users')
created_at = models.DateTimeField(auto_now_add=True)
joined = models.BooleanField(default=False)
def save(self, *args, **kwargs):
if self.id is None and self.created_at is None:
self.created_at = datetime.datetime.now()
self.joined = True
super(Joined, self).save(*args, **kwargs)
#property
def activity_actor_attr(self):
return self.user
Views:
def joined_add(request, pk):
this_goal = Goal.objects.get(pk=pk)
this_goal.add_user_to_list_of_attendees(user=request.user)
return redirect('goaldetail', slug=this_goal.slug)
def joined_delete(request, pk):
this_goal = Goal.objects.get(pk=pk)
this_goal.remove_user_from_list_of_attendees(request.user)
return redirect('goaldetail', slug=this_goal.slug)
def goaldetail(request, slug):
goal = get_object_or_404(Goal, slug=slug)
return render(request, 'goals/detail.html',
{'goal': goal})
Path:
path('joined/<int:pk>', views.joined_add, name='joined_add'),
path('joined-delete/<int:pk>', views.joined_delete, name='joined_delete'),
Create and delete works perfect, but on template this button don't change. I try in many ways and don't know how to do this.
Alright, I'm fairly new to this, I've been working on my Project for a couple months now and I'd like to create URLs that accept multiple parameters to call a View. A sample URL would look like this:
http://www.sample.com/builders//m//
I've got this implemented successfully, by overriding get_object in my DetailView, but I'm wondering if there is a better/easier method for accomplishing this or if this is considered a bad practice. Any guidance would be appreciated.
urls.py
urlpatterns = [
# url(r'^$', builder_list, name='list'),
# url(r'^create/$', builder_create, name='create'),
# url(r'^(?P<slug>[\w-]+)/$', builder_detail, name='detail'),
# url(r'^(?P<slug>[\w-]+)/edit/$', builder_update, name='update'),
# url(r'^(?P<slug>[\w-]+)/delete/$', builder_delete, name='delete'),
# url(r'^$', builder_list, name='sub_list'),
# url(r'^m/create/$', sub_create, name='sub_create'),
url(r'^(?P<builder>[\w-]+)/m/(?P<market>[\w-]+)/$', sub_detail, name='sub_detail'),
# url(r'^m/(?P<slug>[\w-]+)/edit/$', sub_update, name='sub_update'),
# url(r'^m/(?P<slug>[\w-]+)/delete/$', sub_delete, name='sub_delete'),
]
views.py
class BuilderSubDetailView(DetailView):
model = BuilderSub
template_name = "builders/sub_detail.html"
def get_context_data(self, **kwargs):
context = super(BuilderSubDetailView, self).get_context_data(**kwargs)
context['now'] = timezone.now()
print(context)
return context
def get_object(self, queryset=None):
if queryset is None:
queryset = self.get_queryset()
# Next, try looking up by primary key.
builder = self.kwargs['builder']
builder_id = Builder.objects.filter(slug=builder).first().pk
market = self.kwargs['market']
market_id = Market.objects.filter(slug=market).first().pk
if builder is not None and market is not None:
queryset = BuilderSub.objects.filter(parent=builder_id).filter(market=market_id)
# If none of those are defined, it's an error.
if builder is None or market is None:
raise AttributeError("Generic detail view %s must be called with "
"Builder and Market"
% self.__class__.__name__)
try:
# Get the single item from the filtered queryset
obj = queryset.get()
except queryset.model.DoesNotExist:
raise Http404("No %(verbose_name)s found matching the query") % \
{'verbose_name': queryset.model._meta.verbose_name}
return obj
And models.py for reference -- also is there any problem with my get_absolute_url function?
class Builder(models.Model):
added_by = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
company_name = models.CharField(max_length=80, help_text="Full Company Name", unique=True)
short_name = models.CharField(help_text="Short Company Name", max_length=30)
slug = models.SlugField(unique=True)
website = models.CharField(max_length=80, help_text="Format: www.[website].com")
logo = models.ImageField(blank=True, null=True)
timestamp = models.DateTimeField(auto_now_add=True)
info = RedactorField(verbose_name=u'Company Info')
def show_website_url(self):
return format_html("<a href='{url}'>{url}</a>", url=self.website)
def __str__(self):
return self.short_name
class BuilderSub(models.Model):
parent = models.ForeignKey(Builder)
market = models.ForeignKey(Market, null=True, blank=True)
details = RedactorField(verbose_name=u'Details', blank=True, null=True)
main_contact = models.ForeignKey(Person, blank=True, null=True)
def __str__(self):
return "{}: {} - {}".format(self.pk, self.market.name, self.parent.short_name)
def get_absolute_url(self):
return reverse('builders:sub_detail', kwargs={'market': self.market.slug, 'builder': self.parent.slug})
def pre_save_builder_reciever(sender, instance, *args, **kwargs):
instance.slug = slugify(instance.short_name)
pre_save.connect(pre_save_builder_reciever, sender=Builder)
I'm not 100% sure I'm my BuilderSub Model is the appropriate way to handle the Relationship between the overall Builder (company) and the Markets they serve so any guidance there would be appreciated as well.
Yes there is indeed a more ethical way to do this. DetailView is meant to deal with only one object. ListView however gets the job done!
I have replaced builder and market with city and category.
I am also a beginner. Hope I have answered your question :)
views.py
class EntryListView(generic.ListView):
template_name = 'myapp/category.html'
context_object_name = 'entry'
def get_queryset(self):
city_id = self.kwargs['city']
category_id = self.kwargs['category']
entry = Entry.objects.all().filter(city=city_id).filter(category=category_id)
return entry
urls.py
url(r'^(?P<city>[0-9]+)/(?P<category>[0-9]+)/$', views.EntryListView.as_view(), name='entry'),
category.html
{% extends 'myapp/base.html' %}
{% block body %}
<table>
{% for new in entry %}
<tr>
<td>
<img src = "{{new.image_url}}">
<br>
<b>Name :</b> {{new.name}}<br>
{% if new.phone %}
<B>Phone No. :</B> {{new.phone}}<br>
{% endif %}
<b>Address :</b> {{new.address}}<br>
</td>
</tr>
{% endfor %}
{% endblock %}
models.py
class Entry(models.Model):
city = models.ForeignKey(City, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
name = models.CharField(max_length=250)
phone = models.IntegerField(null=True)
address = models.CharField(max_length=250)
image_url = models.CharField(max_length=500)
def __str__(self):
return self.name