How can I display a SingleTableView table together with a DetailView in django? What I want is to include or combine both into one. So that when calling DeviceDetailView i receive the device's details and a table of the devices's data (stored also in another model).
I am using django-tables2 for the table.
Someone any idea?
Thank you
class DataListView(SingleTableView):
model = Data
template_name = 'data/list.html'
table_class = DataTable
def post(self, request, *args, **kwargs):
queryset = request.POST
for i in queryset['list'].split(","):
if queryset['action'] == 'delete':
Data.objects.filter(data_id=i).delete()
return HttpResponseRedirect('/data/')
class DeviceDetailView(DetailView):
template_name = 'devices/detail.html'
def get_object(self):
id_ = self.kwargs.get("id")
return get_object_or_404(Device, id=id_)
EDIT
I know it should look something like this:
class DeviceDetailView(SingleTableView, DetailView):
template_name = "devices/device-detail.html"
model = Device
table_class = DeviceTable
def get_context_data(self, **kwargs):
self.object = self.get_object()
context = super(DetailView, self).get_context_data(**kwargs)
id_ = self.kwargs.get("id")
obj = Device.objects.filter(id=id_)
context['object'] = obj
return context
But i think i still don't know how to do this part inside get_context_data so that the elements are merged together...
SOLUTION
Ok it is donde like this:
class DeviceDetailView(SingleTableView, DetailView):
template_name = 'devices/device-detail.html'
model = Data
table_class = DataTable
#crumbs = [('Device detail', 'DeviceDetailView')]
def get_context_data(self, **kwargs):
self.object = self.get_object()
context = super(DetailView, self).get_context_data(**kwargs)
table = self.get_table(**self.get_table_kwargs())
context[self.get_context_table_name(table)] = table
return context
def get_object(self):
id_ = self.kwargs.get("id")
return get_object_or_404(Device, id=id_)
You can serve the table within your DetailsView using custom get_context_data. You can render your table in the template as you usually do with {% render_table table %}.
# import YourModel
# import YourTable
class DeviceDetailView(DetailView):
model = YourModel
template_name = 'devices/detail.html'
def get_context_data(self, **kwargs):
table = YourTable(YourModel.objects.all()) # define your tables data here
context = {"table": table}
return super().get_context_data(**context)
Related
I've tried this:
class MyClass(LoginRequiredMixin, UpdateView, ListView):
model = models.my_model
fields = ['first_model_field', 'second_model_field']
template_name = 'app/template_name.html'
extra_context = {'second_model': models.second_model.objects.get(pk=self.kwargs['pk']),#didn't work
'third_model':models.third_model.objects.get(pk='pk'),#didn't work
'fourth_model':models.fourth_model.objects.get(foreign_key_id = 'unique_kwarg')}#didn't work.
I also have url's that contain both the /<int:pk>/ kwarg and the /<int:unique_kwarg>/ kwarg.
I am having trouble figuring out how to reference the url **kwarg object.
def form_valid(self, form):
form_template_id = self.kwargs.get(self.pk_url_kwarg)
form.instance.model_id = model.objects.get(pk=form_template_id)
return super().form_valid(form)
and
def get_context_data(self, **kwargs):
"""Insert the form into the context dict."""
if 'unique_kwarg' not in kwargs:
kwargs['unique_kwarg'] = (self.kwargs.get(self.unique_kwarg))
kwargs['model_id'] = (model.objects.get(id=self.kwargs.get(self.unique_kwarg)))
return super().get_context_data(**kwargs)
Two of my views share a substantial amount of code, which makes it hard to maintain. For that reason I decided to move the common code into a custom mixin.
A simplistic example:
class StatisticsMixin(object):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user_products = Product.objects.filter(user=self.request.user).select_related()
context["total_products"] = user_products.count()
context["total_products_open"] = user_products.total_new()
return context
Now, my views would look like this:
class DashboardView(LoginRequiredMixin, StatisticsMixin, TemplateView):
model = Product
template_name = "products/dashboard.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user_products = Product.objects.filter(user=self.request.user).select_related()
# Some other code
return context
class AnalyticsView(LoginRequiredMixin, StatisticsMixin, TemplateView):
model = Product
template_name = "products/analytics.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user_products = Product.objects.filter(user=self.request.user).select_related()
# Some other code
return context
The issue is the following in the custom mixin, StatisticsMixin:
user_products = Product.objects.filter(user=self.request.user).select_related()
which in different views could be something else.
So, I am trying to find a way for the custom mixin, to get the data from the view and not be hardcoded in it.
class StatisticsMixin(object):
def get_user_products(self):
return Product.objects.filter(user=self.request.user).select_related()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user_products = self.get_user_products()
context["total_products"] = user_products.count()
context["total_products_open"] = user_products.total_new()
return context
class DashboardView(LoginRequiredMixin, StatisticsMixin, TemplateView):
model = Product
template_name = "products/dashboard.html"
def get_user_products(self):
return what ever you want
I'm trying to filter an object based off of the primary key in my detailed view. Is there a way I can call my primary key in my views.py or some other way I can filter accordingly? Here's my code:
models.py
class Accounts(models.Model):
account_name = models.CharField(max_length=50)
pricing_id = models.ForeignKey('Pricing')
class OrderRecords(models.Model):
order_id = models.ForeignKey('Orders')
account_id = models.ForeignKey('Accounts')
item_id = models.ForeignKey('Items')
views.py
class AccountDetailView(generic.DetailView):
model = Accounts
template_name = "orders/accountdetail.html"
def get_context_data(self, **kwargs):
context = super(AccountDetailView, self).get_context_data(**kwargs)
context['orderrecords'] = OrderRecords.objects.filter(????????)
return context
Update:
So this was the change I made:
views.py
class AccountDetailView(generic.DetailView):
model = Accounts
template_name = "orders/accountdetail.html"
def get_context_data(self, **kwargs):
pk = self.kwargs['pk']
context = super(AccountDetailView, self).get_context_data(**kwargs)
context['orderrecords'] = OrderRecords.objects.filter(account_id=pk)
return context
Yes, in your views, simply call:
def get_context_data(self, **kwargs):
pk = kwargs.get('pk') # this is the primary key from your URL
# your other code
context = super(AccountDetailView, self).get_context_data(**kwargs)
context['orderrecords'] = OrderRecords.objects.filter(????????)
return context
I have two simple class based generic views which simply render a template. Since they look almost the same and I want to stay dry I wanted to ask you, what would be the smartest and best way to implement this right now:
First View
class Foo(TemplateView):
template_name = "Foo.html"
def get_context_data(self, **kwargs):
user = User.objects.get(username = self.request.user)
context = super(Foo, self).get_context_data(**kwargs)
context['foo_objs'] = Foo.objects.filter(user = user.id)
return context
class Bar(TemplateView):
template_name = "bar.html"
def get_context_data(self, **kwargs):
user = User.objects.get(username = self.request.user)
context = super(Bar, self).get_context_data(**kwargs)
context['bar_objs'] = Bar.objects.filter(user = user.id)
return context
Create intermediate view class with additional attribute model and then inherit your views from it:
class ModelListTemplateView(TemplateView):
model = None
def get_template_names(self):
return [self.model._meta.model_name + '.html']
def get_context_data(self, **kwargs):
context = super(ModelListTemplateView, self).get_context_data(**kwargs)
user = User.objects.get(username=self.request.user)
context['%s_objs' % self.model._meta.model_name] = \
self.model.objects.filter(user=user.id)
return context
class FooView(ModelListTemplateView):
model = Foo
class BarView(ModelListTemplateView):
model = Bar
I have two similar classes, query filter is county code DE or NL.
Is possible to make a objects filter on base of url name and keep only one class? For example, if i point my browser to
127.0.0.1:8000/germany
django will call to filter
feed__country__name='DE'
and
127.0.0.1:8000/netherland
will use
feed__country__name='NL'?
My URL:
url(r'^netherland/$', NLFeedList.as_view(), name='nl'),
url(r'^germany/$', DEFeedList.as_view(), name='de'),
VIEWS:
class NLFeedList(PaginationMixin, ListView):
model = FeedItem
template_name = 'nl_feed.html'
context_object_name = 'feed_items'
paginate_by = 20
def get_queryset(self):
items = FeedItem.objects.filter(feed__country__name='NL')
if self.kwargs.get('category', None):
return items.category(self.kwargs.get('category'))
return items
def get_context_data(self, **kwargs):
context = super(NLFeedList, self).get_context_data(**kwargs)
context['categories'] = Category.objects.filter(country__name='NL')
return context
class DEFeedList(PaginationMixin, ListView):
model = FeedItem
template_name = 'de_feed.html'
context_object_name = 'feed_items'
def get_queryset(self):
items = FeedItem.objects.filter(feed__country__name='DE')
if self.kwargs.get('category', None):
return items.category(self.kwargs.get('category'))
return items
def get_context_data(self, **kwargs):
context = super(DEFeedList, self).get_context_data(**kwargs)
context['categories'] = Category.objects.filter(country__name='DE')
return context
You can do something like:
urls.py
url(r'^(?P<country>germany|netherland)/$', FeedList.as_view(), name='feedlist')
and the view:
class FeedList(PaginationMixin, ListView):
model = FeedItem
context_object_name = 'feed_items'
match = {'germany':'DE','netherland':'NL'}
def get_queryset(self):
code = self.match[self.kwargs['country']]
items = FeedItem.objects.filter(feed__country__name=code)
self.template_name = '%s_feed.html' % code.lower()
if self.kwargs.get('category', None):
return items.category(self.kwargs.get('category'))
return items
def get_context_data(self, **kwargs):
context = super(FeedList, self).get_context_data(**kwargs)
context['categories'] = Category.objects.filter(country__name=self.match[self.kwargs['country']])
return context
Also, perhaps you don't need two templates else only one, in this case just remove this line self.template_name = '%s_feed.html' % code.lower() and set the template_name accordingly.
Change your url to
url(r'^(?P<country>netherland|germany)/$', NLFeedList.as_view(), name='nl'),
Then access this new <country> parameter in your view using
country = self.kwargs['country']
Then do the necessary if country = '...': code block in your view.