I got a question. I'm wondering what's the easiest way to add different {{ variable }} from different related model in one template.
I'd like to add some information related to seller rating:
def total_seller_ratings(self):
return self.seller.rating_seller.count()
def avg_seller_ratings(self):
return self.seller.annotate(avg_ratesugar=Avg('rating_seller__ratesugar')).order_by('-avg_ratesugar')
Create a template tag from Middleware? Or is any fastes solution to add another model on my view?
I got a main view for my main page:
#Channel MAIN PAGE
#method_decorator(login_required(login_url='/cooker/login'),name="dispatch")
class ChannelMainPage(generic.DetailView, FormMixin):
model = Channel
context_object_name = 'channel'
template_name = 'channel_detail.html'
form_class = ChannelChatForm
def get_context_data(self, **kwargs):
context = super(ChannelMainPage, self).get_context_data(**kwargs)
context['form'] = self.get_form()
return context
def form_valid(self, form):
if form.is_valid():
form.instance.channel = self.object
form.instance.user = self.request.user
form.save()
return super(ChannelMainPage, self).form_valid(form)
else:
return super(ChannelMainPage, self).form_invalid(form)
def post(self,request,*args,**kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_valid(form)
def get_success_url(self):
return reverse('channel:channel_detail',kwargs={"slug":self.object.slug})
models.py
class Channel(models.Model):
consumer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="channel_consumer", blank=True, null=True)
name = models.CharField(max_length=10)
seller = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="channel_seller")
image = models.ImageField(null=True,blank=True,default='user/user-128.png', upload_to='channel/')
date_created = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField('Make it happen', default=False)
class Rating(models.Model):
channel = models.OneToOneField(Channel,on_delete=models.CASCADE,related_name="rating_channel")
consumer = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.CASCADE,related_name='rating_consumer')
seller = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.CASCADE,related_name='rating_seller')
is_rated = models.BooleanField('Already rated', default=True)
comment = models.TextField(max_length=200)
publishing_date = models.DateTimeField(auto_now_add=True)
ratesugar = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)])
def __str__(self):
return self.channel.name
One place to add it is on the Model class. This is already available as a variable within the context (see generic.Detailview.get_context_data). It is named "object" and can then be accessed through the templating mechanics.
class Channel(models.Model):
consumer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="channel_consumer", blank=True, null=True)
name = models.CharField(max_length=10)
seller = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="channel_seller")
image = models.ImageField(null=True,blank=True,default='user/user-128.png', upload_to='channel/')
date_created = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField('Make it happen', default=False)
def some_method():
pass
template.html
<div>{{ object.some_method() }}</div>
Finally, on the discussion (code design) of which model to place the desired methods on...
If you want to calculate the average over ALL ratings it belongs on the User model.
If you want an average over the ratings over a given channel then it belongs on the Channel model.
Good luck.
PS. Don't forget to prefetch_related to have avoid slow queries!
Related
I have created a form named as AttendanceForm :
class AttendanceForm(forms.ModelForm):
class Meta:
model = Attendance
fields = '__all__'
These are models
class Employee(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
eid = models.IntegerField(primary_key=True)
salary = models.IntegerField()
gender = models.CharField(max_length=6, choices=GENDER_CHOICES, default=1)
contactno = models.CharField(max_length=10)
email = models.CharField(max_length=30)
country = models.CharField(max_length=30)
city = models.CharField(max_length=20)
pincode = models.IntegerField()
address = models.CharField(max_length=60)
def __str__(self):
return self.user.first_name + ' ' + self.user.last_name
class Attendance(models.Model):
employee = models.ForeignKey(Employee, on_delete=models.CASCADE, default=1)
attendancedate = models.DateField()
in_time = models.TimeField()
out_time = models.TimeField()
description = models.TextField()
def __str__(self):
return str(self.employee)
view for attendance.
#csrf_exempt
def addattendance(request):
form = AttendanceForm()
emp_list = Employee.objects.all()
if request.method == 'POST':
form = AttendanceForm(request.POST)
if form.is_valid():
form.save(commit=True)
return redirect('employee/detail_attendance')
return render(request, 'employee/addattendance.html', {'form': form, 'emp_list': emp_list})
I tried everything, but I don't know why the data is not saving into the database. Also, models are created fine, and the main thing is that there are no errors coming up.
Please let me know if any changes are required.
I can suggest simple solution with Class-Based-Views:
from django.views.generic.edit import FormView
def AddAttendanceFormView(FormView):
form_class = AttendanceForm
extra_context = {"emp_list": Employee.objects.all()}
success_url = reverse_lazy('employee/detail_attendance')
template_name = 'employee/addattendance.html'
def post(self, *args, **kwargs):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
return self.form_invalid(form)
Remember, that in urls.py you need to use .as_view() for class based views, like:
path((...), AddAttendanceFormView.as_view())
Also, you will not need #csrf_exempt, just put {% csrf_token %} anywhere inside your form's template.
I tried several ways to solve the problem but I couldn't .. every time I got it error. Item added to DB but error message returned on page.
why "get_absolute_url" and "success_url" do not work?
View
class AddItemView(CreateView):
model = Add_Item
form_class = AddItemForm
template_name ='add_item.html'
success_url = reverse_lazy("home")
def form_valid(self, form):
self.object = form.save(commit=False)
# Add_Item.User = User
self.object.user = self.request.user
self.object.save()
Models
class Add_Item(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE, default=None,
null=True)
title = models.CharField(max_length=255)
categories = models.CharField(max_length=255 , choices=all_categories)
description = RichTextField(blank=True,null=True)
condition = models.CharField(max_length=100, choices=cond)
city = models.CharField(max_length=50, choices=cy.city, blank=True)
street = models.CharField(max_length=100, blank=True)
home_number = models.CharField(max_length=100, blank=True)
header_img = models.ImageField(null=True, blank=True, upload_to='img/')
more_img = models.ImageField(null=True, blank=True, upload_to='img/')
Pub_date = models.DateField(auto_now_add=True)
def __str__(self):
return str(self.title)
def get_absolute_url(self):
return reverse('home')
From the docs:
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
return super().form_valid(form)
You need to add the return line.
I have a model form that creates a new job entry, and on submission, I need an invisible field job_time_estimation to be set to a sum of 'service_stats_estimate_duration' values from ServiceItemStats objects associated with the JobEntry by a many-to-many relationship when submitting the form.
For example, if in my NewJobEntryForm I chose two existing ServiceItemStats objects that have service_stats_estimate_duration values 60 and 90, on submission, I want a value 150 to be saved in that JobEntry object's job_time_estimation attribute.
I tried doing this using aggregation by defining a save() method in the model but I am getting an error "name 'serviceItemStats' is not defined".
I am not sure if I am going about this the right way. Any help would be appreciated.
My code:
models.py:
class ServiceItemStats(models.Model):
service_stats_name = models.CharField(primary_key=True, max_length=20)
service_stats_estimate_duration = models.IntegerField()
# Many-to-many relationship with JobEntry.
def __str__(self):
return self.service_stats_name
class JobEntry(models.Model):
# PK: id - automatically assigned by Django.
jo
b_entry_date_time = models.DateTimeField(default=timezone.now)
jo
b_date = models.DateField(blank=True, null=True)
job_checked_in = models.BooleanField()
job_checked_out = models.BooleanField(default=False)
job_priority = models.IntegerField()
job_time_estimation = models.IntegerField(blank=True, null=True)
job_comments = models.TextField(max_length=200, blank=True, null=True)
job_parts_instock = models.BooleanField(default=False)
job_started = models.BooleanField(default=False)
job_finished = models.BooleanField(default=False)
job_expand_fault_evidence = models.ImageField(blank=True, null=True)
job_expand_comments = models.ImageField(blank=True, null=True)
job_expand_parts_required = models.CharField(max_length=200, blank=True, null=True)
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE) #One-to-one relationship
customer = models.ForeignKey(Customer, on_delete=models.CASCADE) #One-to-one relationship
serviceBay = models.ForeignKey(ServiceBay, on_delete=models.CASCADE, blank=True, null=True) #One-to-one relationship
serviceItemStats = models.ManyToManyField(ServiceItemStats, blank=True) #Many-to-many relationship
def __str__(self):
return self.id
def save(self, *args, **kwargs):
if not self.job_time_estimation:
self.job_time_estimation = serviceItemStats.objects.all().aggregate('service_stats_estimate_duration')
return super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse("jobs:job_detail",kwargs={'pk':self.pk})
views.py
class JobCreateView(FormView):
template_name = "jobs/jobentry_form.html"
form_class = NewJobEntryForm
success_url = reverse_lazy("jobs:job_list")
def form_valid(self, form):
form.save()
return super(job_list, self).form_valid(form)
forms.py
class NewJobEntryForm(ModelForm):
class Meta:
model = JobEntry
fields = ['vehicle', 'customer', 'job_date', 'job_checked_in', 'job_priority', 'job_comments', 'job_parts_instock', 'serviceItemStats']
widgets = {
'job_date' : forms.DateInput(format=('%m/%d/%Y'), attrs={'class':'form-control', 'placeholder':'Select a date', 'type':'date'}),
'ServiceItemStats' : forms.CheckboxSelectMultiple(),
'job_priority' : forms.RadioSelect(choices=priorityOptions),
}
You can try this.
from django.db.models import Sum
class JobCreateView(FormView):
template_name = "jobs/jobentry_form.html"
form_class = NewJobEntryForm
success_url = reverse_lazy("jobs:job_list")
def form_valid(self, form):
job=form.save()
estimation = job.serviceItemStats.all().aggregate(total=Sum('service_stats_estimate_duration'))
job.job_time_estimation = estimation['total']
job.save()
return super(job_list, self).form_valid(form)
I am setting up my CategoryDetailView for my CRM. Then this error occurred:
'CategoryDetailView' object has no attribute 'get_object'
here's my code sectrion from views.py:
class CategoryDetailView(LoginRequiredMixin, generic.ListView):
template_name = "clients/category/category_detail.html"
context_object_name = "category"
def get_context_data(self, **kwargs):
context = super(CategoryDetailView, self).get_context_data(**kwargs)
clients = self.get_object().client_set.all()
context.update({
"clients": clients
})
return context
Here's my models.py
class Client(models.Model):
first_name = models.CharField(max_length=30)
middle_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
mobile_number = models.CharField(max_length=12)
organization = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
agent = models.ForeignKey("Agent", null=True, blank=True, on_delete=models.SET_NULL)
category = models.ForeignKey("Category", related_name="clients", null=True, blank=True, on_delete=models.SET_NULL)
class Category(models.Model):
name = models.CharField(max_length=30) # New, Tapped, Active, Closed
organization = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
def __str__(self):
return self.name
Thanks in advance!
You are working with a ListView [Django-doc], not a DetailView [Django-doc], and a ListView indeed has no .get_object(…) method [Django-doc]. You furthermore should specify a model = … or queryset = … to specify with what queryset the DetailView is dealing.
You thus should inherit from the DetailView. You can also work with self.object to prevent making an extra query:
from django.views.generic import DetailView
class CategoryDetailView(LoginRequiredMixin, DetailView):
template_name = 'clients/category/category_detail.html'
context_object_name = 'category'
model = Category
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
clients = self.object.client_set.all()
context['clients'] = clients
return context
There is als no reason to add this to the context, in the template, you can simply work with:
{% for client in category.client_set.all %}
{{ client }}
{% endfor %}
I am creating a wiki and need to put in values in the model called revision. This table has a foreigkey to wikipage.
My problem is that I am unable to insert values in the revision model.
I have tried using def form_valid(self, form) like you would when entering user, without any luck.
Models.py
class Wikipage(models.Model):
title = models.CharField(max_length=100)
date_created = models.DateTimeField('Created', auto_now_add=True)
def __str__(self):
return self.title
class Meta:
verbose_name_plural = "Wikipages"
class Revision(models.Model):
wikipage = models.ForeignKey(Wikipage, null=True, on_delete=models.CASCADE, related_name='revisions')
content = models.TextField('Content')
author = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
last_edit = models.DateTimeField('Last Edited', auto_now=True)
comment = models.TextField('Comment', blank=True)
class Meta:
verbose_name = 'Revision'
verbose_name_plural = 'Revisions'
ordering = ['-last_edit']
get_latest_by = ['last_edit']
def __str__(self):
return self.content
View.py
Class WikipageCreateView(CreateView):
template_name = 'wiki/wikipageform.html'
model = Wikipage
fields = ['title']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
The template are as simple as possible with {{ form.as_p }} and all the necessary stuff.