i am getting this attribute error (function has no attribute all) when i clicked on a question in my browser after running my server. I have gone through the code many times but couldn't find the error.
View.py
class IndexView(generic.ListView):
template_name ='pulls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""
Return the last five published questions (not including those set to be
published in the future).
"""
return Question.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:5]
#Detail Function
class DetailView(generic.DetailView):
model = Question
template_name ='pulls/detail.html'
def queryset(self):
"""
Excludes any questions that aren't published yet.
"""
return Question.objects.filter(pub_date__lte=timezone.now())
Based on the doc, the generic.DetailView inherits methods and attributes from 5 views, including SingleObjectTemplateResponseMixin and BaseDetailView.
BaseDetailView is a base view for displaying a single object... .
So, if you are showing more than one object it is better that do not use DetailView. Otherwise, as it is written in the code, you should override self.get_object().
Related
I came across this error in my django application after hitting submit on a create or edit form:
No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model..
This was confusing because I have a get_success_url passed down through inheritance. To be clear, I have found the issue, but have no earthly idea why my solution worked.
Here was the code causing the error inside
.../views.py:
class FormViews():
model = Ticket
form_class = TicketForm
def get_success_url(self):
return reverse('tickets:index')
class TicketCreate(CreateView, FormViews):
template_name = 'tickets/ticket_create_form.html'
model = Ticket
form_class = TicketForm
class TicketUpdate(UpdateView, FormViews):
model = Ticket
form_class = TicketForm
template_name_suffix = '_update_form'
I created the FormViews class so there would not be any repeated code for the model, form_class, and get_success_url.
I was able to resolve this error by switching the parameters in my function definitions:
class TicketCreate(CreateView, FormViews) became class TicketCreate(FormViews, CreateView)
class TicketUpdate(UpdateView, FormViews) became class TicketUpdate(FormViews, UpdateView)
This fixed it. Now I redirect to the index page without any issues. Why is it that the get_success_url is recognized after switching the listed parent classes? I would have thought that the attributes and functions are inherited and recognized by Django regardless of order. Is this a Python or Django related issue?
In python every class has something called an MRO (Method Resolution Order), this explains it pretty well. Your FormViews (also for the most part classes in python are singular) is more of a mixin, I would call it as such: FormViewMixin.
Since CreateView and UpdateView are proper classes that have get_success_url defined, the order ABSOLUTELY matters. So I would put the things you want "discovered", first.
class TicketCreateView(FormViewMixin, CreateView):
...
is what you want.
I've implemented a filter using the django-filters third party framework but want to run the filter on an already filtered set which was giving errors.
class BlogView(ListView):
template_name="blog/blog.html"
model = Post
# def get_queryset(self):
# return Post.objects.filter(posted_date__lte=timezone.now()).order_by("-posted_date")[:25]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filter'] = PostFilter(self.request.GET, queryset=self.get_queryset())
return context
my view ^ my filter v
class PostFilter(django_filters.FilterSet):
class Meta:
model = Post
fields = ["title"]
My blog needs the ability to schedule posts in the future meaning when i display them i am filtering posts by posted_date__lte=timezone.now()
however this is causing a problem when i am then using the filter because i cannot filter an already spliced object. I've read through and understand the problem comes from the way the database works so i am looking for an alternative way to make only posts that posted_date__lte=timezone.now() show without using the currently commented out def get_queryset filter i was previously using.
edit* maybe in the line:
context['filter'] = PostFilter(self.request.GET, queryset=SOMETHINGHERE()) i can add the filter to SOMETHINGHERE in some way?
I tried about 25 Stackoverflow links and nobody seems to have a working solution for this problem.
I created a custom queryset like this:
class ProjectQuerySet(models.QuerySet):
def get_active(self):
from apps.projectmanagement.models import Project
return self.filter(active=True)
class ProjectManager(models.Manager):
def get_queryset(self):
return ProjectQuerySet(self.model, using=self._db)
This works great if I start at the model like
Project.objects.get_active()
But if I want to use it in a relation, no luck so far:
employee.projects.get_active()
I always get this error:
AttributeError: 'ManyRelatedManager' object has no attribute 'get_active'
What I've tried so far:
I read that use_for_related_fields = True in the manager class is deprecated. Does not work anyway on django v2.1
Adding this in my model, as half the internet states:
class Project(models.Model):
...
objects = ProjectManager()
class Meta:
base_manager_name = 'objects'
Trying to avoid the RelatedManager and to work with a queryset:
employee.projects.all().get_active()
Any ideas what I've been doing wrong? And how would I solve this? Can't be too hard, right?
As the docs state, "Base managers aren’t used when querying on related models". The example they give is for going in the other direction, ie project.employee.
There is no way to do this using managers themselves. The best bet is to define a method on your model:
class Employee(models.Model):
...
def get_active_projects(self):
return self.projects.filter(active=True)
# or
return Project.objects.filter(employee=self).get_active()
I have written a Class based view which acts as a base view for several other class based views. So the other class based views is just subclassing the base view, but the subclassed views are not getting the effect of the get_context_data or form_valid functions, so the context variables set in the base view is not getting sent to the template when requests are executing using the view subclassing the base view, they are only being sent when the base view itself it used.
Class based view:
class PortfolioNewBase(CreateView):
url_name = ''
post_req = False
def form_valid(self, form):
self.post_req = True
return super(PortfolioNewBase, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(PortfolioNewBase, self).get_context_data(**kwargs)
context['profile_id'] = self.kwargs['profile_id']
context['post_req'] = self.post_req
return super(PortfolioNewBase, self).get_context_data(**kwargs)
def get_success_url(self):
return reverse(self.url_name, args=self.kwargs['profile_id'])
When creating a new class based view which is one of the views that will be using this code it does not get access to the "profile_id" or "post_req" variables for some reason, it does not get sent to the template, but if you only use the base view written above that view will send the variables so that they are available in the view.
Code for one of the class based views using this base view written above:
class PortfolioNewDividend(PortfolioNewBase):
model = Dividend
form_class = DividendForm
template_name = 'plan/portfolio/new/new_dividend.html'
url_name = 'plan:investment-info-dividends-new'
The form works and everything, but the variables in the get_context_data in the parent is apparently not being inherited for some reason which is kind of the point here and the form_valid function is not being run either, the value of the post_req on POST requests done by the PortfolioNewDividend class based view still has the value False.
Why is the PortfolioNewDividend not running the get_context_data and form_valid functions when a request is executed with that view but the functions run if you use the base clase (written above) only ?
One super call too many in there. Change as follows:
def get_context_data(self, **kwargs):
context = super(PortfolioNewBase, self).get_context_data(**kwargs)
context['profile_id'] = self.kwargs['profile_id']
context['post_req'] = self.post_req
return context # You must actually return the modified context!
Is it possible to build a custom model field/widget combination which displays a value but never writes anything back to the database? I would use this widget exclusively in the admin's forms.
I wrote my own field, which overwrites the formfield() method to declare its own widget class. It displays just fine, but as soon as the 'Save' button is clicked in the admin, I'm getting a validation error:
This field is required.
That makes sense, considering that my widget didn't render out a form field. However, what I'd like to do is basically remove this field from the update process: whenever used in the admin, it just shouldn't be mentioned in the SQL UPDATE at all.
Is that possible?
Here's a sketch of the code I have so far:
class MyWidget(Widget):
def render(self, name, value, attrs=None):
if value is None:
value = ""
else:
# pretty print the contents of value here
return '<table>' + ''.join(rows) + '</table>'
class MyField(JSONField):
def __init__(self, *args, **kwargs):
kwargs['null'] = False
kwargs['default'] = list
super(MyField, self).__init__(*args, **kwargs)
def formfield(self, **kwargs):
defaults = {
'form_class': JSONFormField,
'widget': MyWidget,
}
defaults.update(**kwargs)
return super(MyField, self).formfield(**defaults)
UPDATE 1: The use case is that the field represents an audit log. Internally, it will be written to regularly. The admin however never needs to write to it, it only has to render it out in a very readable format.
I'm not using any other ModelForms in the application, so the admin is the only form-user. I don't want to implement the behavior on the admin classes themselves, because this field will be reused across various models and is always supposed to behave the same way.
There are multiple ways to create a read-only field in the admin pages. Your requirements on the database storage are a bit fuzzy so I go through the options.
You have to register an AdminModel first in admin.py:
from django.contrib import admin
from yourapp.models import YourModel
class YourAdmin(admin.ModelAdmin):
pass
admin.site.register(YourModel, YourAdmin)
Now you can add different behavior to it. For example you can add the list of fields shown in the edit/add page:
class YourAdmin(admin.ModelAdmin):
fields = ['field1', 'field2']
This can be names of the model fields, model properties or model methods. Methods are displayed read-only.
If you want to have one field read-only explicitly add this:
class YourAdmin(admin.ModelAdmin):
fields = ['field1', 'field2']
readonly_fields = ['field2']
Then you have the option to overwrite the display of the field completely by adding a method with the same name. You will not even need a model field/method with that name, then:
class YourAdmin(admin.ModelAdmin):
fields = ['field1', 'field2']
readonly_fields = ['field2']
def field2(self, obj):
return '*** CLASSIFIED *** {}'.format(obj.field2)
With django.utils.safestring.mark_safe you can return HTML code as well.
All other options of the Admin are available, except the widget configuration as it applies to the writable fields only.
I might be a little confused as to what you want but you might want to look into model properties. Here is an example for my current project.
Code inside your model:
class Textbook(models.Model):
#other fields
#property
def NumWishes(self):
return self.wishlist_set.count()
Then you can just display it on the admin page.
class Textbook_table(admin.ModelAdmin):
fields = ["""attributes that are saved in the model"""]
list_display = ("""attributes that are saved in the model""", 'NumWishes'')
So now I can display NumWishes in the admin page but it doesn't need to be created with the model.
Hello in the class admin modify the permission method
#admin.register(my_model)
class My_modelAdmin(admin.ModelAdmin):
def has_delete_permission(self, request, obj=None):
return False
def has_change_permission(self, request, obj=None):
return False