Django, getting data in different page from view - django

Hello I am new to Django, I am currently working on a project but I can`t figure out how I should do something.
Right now I am at the page
home/stats/ID/LANGUAGE
but inside this page I want a "edit" button, once clicked I want to go to:
home/stats/ID/LANGUAGE/edit/
I just want to get the same data from home/stats/ID/LANGUAGE again, but now in home/stats/ID/LANGUAGE/edit/
My view.py:
class StatsView(TemplateView):
template_name = 'home/stats.html'
analytics = build('analyticsreporting', 'v4', credentials=credentials)
def get(self, request, id, language):
min_date = "2018-12-01"
date01 = datetime.strptime(min_date, '%Y-%m-%d')
max_date = "2018-12-31"
date02 = datetime.strptime(max_date, '%Y-%m-%d')
print(date01)
print(date02)
if request.GET.get('date1'):
date1 = request.GET.get('date1')
pol1 = datetime.strptime(date1, '%Y-%m-%d')
date01 = pol1
print(date01)
if request.GET.get('date2'):
date2 = request.GET.get('date2')
pol2 = datetime.strptime(date2, '%Y-%m-%d')
date02 = pol2
print(date02)
if request.user.is_authenticated:
current_user = request.user.id
result = BlablaAuth.objects.filter(user=request.user)
if language == 'ALL':
blabla = Blabla.objects.filter(blabla=id)
prefix = '/blabla/' + id
if result and blabla.count() > 0:
analytics_result1 = self.analytics.reports().batchGet(
body={
"Google analytics reporting stuff"
analytics_result2 = self.analytics.reports().batchGet(
body={
"Google Reporting stuff"
return render(request, self.template_name, context={
"report1": analytics_result1.execute(),
"report2": analytics_result2.execute()
})
else:
apple = Apple.objects.filter(video=id)
prefix = '/apple/' + id
if result and apple.count() > 0:
analytics_result1 = self.analytics.reports().batchGet(
body={
"Google reporting analytics stuff"
analytics_result2 = self.analytics.reports().batchGet(
body={
"Google reporting analytics stuff"
return render(request, self.template_name, context={
"report1": analytics_result1.execute(),
"report2": analytics_result2.execute()
})
My urls.py:
from django.conf.urls import url
from django.contrib import admin
from home.views.views import HomeView, StatsView
from .views import views
from django.contrib.auth.decorators import login_required
app_name = "home"
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^stats/(?P<id>[0-9]+)/(?P<language>[a-zA-Z]+)/$',
login_required(StatsView.as_view()), name='stats'),
url(r'^stats/(?P<id>[0-9]+)/(?P<language>[a-zA-Z]+)/edit/$',
StatsView.edit_stats, name='stats_edit'),
url(r'^$', login_required(HomeView.as_view()), name='home'),
]
My button in stats.html:
<button><a href="{% url home:stats_edit auth.blabla.id apple.language %}">Edit</button>

Assuming your edit view will be based on a generic CBV (e.g. UpdateView), you can create a Mixin class that has a method get_context_data(self, **kwargs) and does all the stuff you now do in the get() method of your TemplateView. This method will automatically get called by your TemplateView and UpdateView and add the context to your rendering.
class AnalyticsMixin(object):
analytics = None # or some default that can be used by all subclasses.
# None is not a good default since it will raise an AttributeError when calling self.analytics.reports()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# all the stuff you do in get() method, using self.request and self.kwargs which are set by the `as_view()` method on the CBV
request = self.request
id = self.kwargs.get('id')
language = self.kwargs.get('language')
...
return context.update({
"report1": analytics_result1.execute(),
"report2": analytics_result2.execute()
})
then in your views:
class StatsView(AnalyticsMixin, TemplateView):
template_name = ...
analytics = ... # override here or if it depends on the request override in a method
# remove the get() method unless you do something that's not for both views.
# e.g. to override self.analytics if credentials depends on request
def get_context_data(self, **kwargs):
self.analytics = build('analyticsreporting', 'v4', credentials=self.get_credentials())
return super().get_context_data(**kwargs)
and for your edit view:
class EditStatsView(AnalyticsMixin, UpdateView):
template_name = ...
model = ... # name of model to update
# here add the form_class for the editing form if you customise it
# the context will have the form + the data from get_context_data()

way to pass data between two view is session . django support authenticate as well as anonymous session. just store the data as session key and retrieve it when ever you need it.

Related

How can use slug for all urls in django without anything before or after?

I want all djaango urls use slug field without any parameter before or after, by default
just one url can use this metod
Views.py
class ArticleDetail(DetailView):
def get_object(self):
slug = self.kwargs.get('slug')
article = get_object_or_404(Article.objects.published(), slug=slug)
ip_address = self.request.user.ip_address
if ip_address not in article.hits.all():
article.hits.add(ip_address)
return article
class CategoryList(ListView):
paginate_by = 5
template_name = 'blog/category_list.html'
def get_queryset(self):
global category
slug = self.kwargs.get('slug')
category = get_object_or_404(Category.objects.active(), slug=slug)
return category.articles.published()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['category'] = category
return context
urls.py
urlpatterns = [
path('<slug:slug>', ArticleDetail.as_view(), name="detail"),
path('<slug:slug>', CategoryList.as_view(), name="category"),
]
This is my django blog codes,
I don't want write article or category & ... in urls, just slug
mysite .com/article-slug
...
mysite .com/category-slug
It will always trigger the Article view, regardless if there is an Article for that slug. You thus should make the URL patterns non-overlapping such that the other views can be triggered, for example with:
path('article/<slug:slug>/', Article.as_View(), name="articledetail"),
path('category/<slug:slug>/', Category.as_View(), name="category"),
path('product/<slug:slug>/', Product.as_View(), name="productdetail"),
If you want a path that accepts a single slug, you should define a view that looks if there is an Article with that slug, if that is not the case a Category and if that is not the case a Product you thus implement that logic in the view, not in the URL patterns.
#WillemVanOlsem is right, you will have to write a view like this:
from django.http import HttpResponseNotFound
def slug_router(request, slug):
if Category.objects.filter(slug=slug).exists():
return CategoryList.as_view()(request, slug=slug)
elif Article.objects.filter(slug=slug).exists():
return ArticleDetail.as_view()(request, slug=slug)
else:
return HttpResponseNotFound('404 Page not found')
And then
urlpatterns = [
path('<slug:slug>', slug_router, name="slug"),
]
... if I'm not mistaken. This should be the jist of it.
I didn't test this code, just typed it in here, so let me know if it doesn't work, I'll help to fix it.
Note that you'll have a preference if there are Articles with the same slug as some Categories.

Django update index after adding records to db programmatically

I added a number of records to a Django db table (machina forums) directly via a script (ie: I did not use the site admin interface). The structure seemed fairly straightforward with no foreign keys in other tables.
However the resulting displays are uneven. In a forum index display all of the children forums display under a category. However if I go into the category, only forums added via the admin interface are visible. There does not appear to be any difference in the db records between those that were added programmatically and those added via the admin interface.
I am guessing the issue has to do with indexes on the table. However when I use a GUI to view the db all of the indexes show "result set is empty."
Any ideas about what is causing the problem and if it is index related, how do I update the index?
Here is the view that creates the forum displays:
Forum views
===========
This module defines views provided by the ``forum`` application.
"""
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.views.generic import ListView
from machina.apps.forum.signals import forum_viewed
from machina.conf import settings as machina_settings
from machina.core.db.models import get_model
from machina.core.loading import get_class
Forum = get_model('forum', 'Forum')
Topic = get_model('forum_conversation', 'Topic')
ForumVisibilityContentTree = get_class('forum.visibility', 'ForumVisibilityContentTree')
PermissionRequiredMixin = get_class('forum_permission.viewmixins', 'PermissionRequiredMixin')
TrackingHandler = get_class('forum_tracking.handler', 'TrackingHandler')
class IndexView(ListView):
""" Displays the top-level forums. """
context_object_name = 'forums'
template_name = 'forum/index.html'
def get_queryset(self):
""" Returns the list of items for this view. """
return ForumVisibilityContentTree.from_forums(
self.request.forum_permission_handler.forum_list_filter(
Forum.objects.all(), self.request.user,
),
)
def get_context_data(self, **kwargs):
""" Returns the context data to provide to the template. """
context = super(IndexView, self).get_context_data(**kwargs)
visiblity_content_tree = context['forums']
# Computes some global values.
context['total_posts_count'] = sum(n.posts_count for n in visiblity_content_tree.top_nodes)
context['total_topics_count'] = sum(
n.topics_count for n in visiblity_content_tree.top_nodes
)
return context
class ForumView(PermissionRequiredMixin, ListView):
""" Displays a forum and its topics. If applicable, its sub-forums can also be displayed. """
context_object_name = 'topics'
paginate_by = machina_settings.FORUM_TOPICS_NUMBER_PER_PAGE
permission_required = ['can_read_forum', ]
template_name = 'forum/forum_detail.html'
view_signal = forum_viewed
def get(self, request, **kwargs):
""" Handles GET requests. """
forum = self.get_forum()
if forum.is_link:
response = HttpResponseRedirect(forum.link)
else:
response = super(ForumView, self).get(request, **kwargs)
self.send_signal(request, response, forum)
return response
def get_forum(self):
""" Returns the forum to consider. """
if not hasattr(self, 'forum'):
self.forum = get_object_or_404(Forum, pk=self.kwargs['pk'])
return self.forum
def get_queryset(self):
""" Returns the list of items for this view. """
self.forum = self.get_forum()
qs = (
self.forum.topics
.exclude(type=Topic.TOPIC_ANNOUNCE)
.exclude(approved=False)
.select_related('poster', 'last_post', 'last_post__poster')
)
return qs
def get_controlled_object(self):
""" Returns the controlled object. """
return self.get_forum()
def get_context_data(self, **kwargs):
""" Returns the context data to provide to the template. """
context = super(ForumView, self).get_context_data(**kwargs)
# Insert the considered forum into the context
context['forum'] = self.get_forum()
# Get the list of forums that have the current forum as parent
context['sub_forums'] = ForumVisibilityContentTree.from_forums(
self.request.forum_permission_handler.forum_list_filter(
context['forum'].get_descendants(), self.request.user,
),
)
# The announces will be displayed on each page of the forum
context['announces'] = list(
self.get_forum()
.topics.select_related('poster', 'last_post', 'last_post__poster')
.filter(type=Topic.TOPIC_ANNOUNCE)
)
# Determines the topics that have not been read by the current user
context['unread_topics'] = TrackingHandler(self.request).get_unread_topics(
list(context[self.context_object_name]) + context['announces'], self.request.user,
)
return context
def send_signal(self, request, response, forum):
""" Sends the signal associated with the view. """
self.view_signal.send(
sender=self, forum=forum, user=request.user, request=request, response=response,
)
Seems like you're talking about some custom solution and it is hard to help without additional details like SQL queries that you've applied, model code, queries, and their returns.

Django Encrypt the URL (PK and ID)

I am trying to find best solution for encrypting my URL, I have found some old versions, for python 2.2.
I need to set my URLs, not to display like this:
.com/AddPost/1/ and .com/PostDetail/40.
But something like this:.com/AddPost/DMQRzZWMDdGQtbndzBHNsawN0aXRsZQR0ZXN0AzcwMQR3b2UDMjQwMjEwNQ
That you can not guess what PK is and access that page:
URLs:
urlpatterns = [
path('PostDetail/<int:pk>', PostDetail.as_view(), name ='post_detail'), ]
view.py:
class PostDetail(DetailView):
model = Post
template_name = 'post_detail.html'
def get_context_data(self, *args,**kwargs):
post = Post.objects.all()
context = super(PostDetail,self).get_context_data(*args,**kwargs)
stuff = get_object_or_404(Post,id=self.kwargs['pk'])
total_likes=stuff.total_likes()
context['total_likes'] = total_likes
return context

How to pass data to a class based view's method?

I am trying to figure out how I can pass data from a form to the method of a class based view that serves as a API endpoint.
Homepage view (has a form to enter a stock ticker):
def home(request):
# data = get_stock_data('TSLA', key)
if request.method == 'POST':
form = TickerForm(request.POST)
if form.is_valid():
ticker = form.cleaned_data['ticker']
stock_data = get_stock_data(ticker, api_key)
return redirect('chart-data', ticker=ticker) # this line I am having trouble with
else:
form = TickerForm()
stock_data = None
return render(request, 'app/home.html', {'data': stock_data, 'form':form})
The API View:
class ChartData(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, ticker, format=None):
# get stock data
stock_data = get_stock_data(ticker, api_key) # how do I pass the ticker?
labels = []
default_items = []
# get label & values
for key, value in stock_data.items():
labels.append(key)
default_items.append(value['4. close'])
# prepare data
data = {
'labels': labels[::-1],
'default_items': default_items[::-1]
}
return Response(data)
urls.py
urlpatterns = [
path('', views.home, name="homepage"),
path('api/chart/data', views.ChartData.as_view(), name="chart-data"),
]
Then I get the data with Javascript and display the graph on the frontend, which works fine. The only thing I can't figure out how to pass the ticker argument to the get method of my ChartData view. I hope my problem is clear.
return redirect('chart-data', {'ticker':ticker})
Have to use a dictionary, I believe ...
You should include ticker in the url path.
path('api/chart/data/<slug:ticker>/', views.ChartData.as_view(), name="chart-data"),
This assumes ticker is a string like 'TSLA'.

How to pass created object in createview right to updateview in django

I have a createview view in my django app:
### Create a Group
class GroupCreateView(CreateView): # {{{
model = Group
form_class = GroupForm
template_name = 'ipaswdb/group/group_form.html'
success_url = '/ipaswdb/group/'
def get_context_data(self, **kwargs):
..do stuff..
def post(self, request, *args, **kwargs):
if self.request.POST.has_key('submit'):
form = GroupForm(request.POST)
if form.is_valid():
### Save the group
self.object = form.save()
#### Adding a provider forces a default location
#if form['default_location'].value() == True:
### We are forcing the creation of a GroupLocation when a new Group is created
gl = GroupLocation(
group = Group.objects.get(pk=self.object.id),
doing_business_as = self.object.group_name,
default_group_location = True,
mailing_address_line_one = self.object.mailing_address_line_one,
mailing_address_line_two = "",
mailing_city = self.object.mailing_city,
mailing_state = self.object.mailing_state,
mailing_zip_code = self.object.mailing_zip_code,
mailing_phone = self.object.mailing_phone,
mailing_fax = self.object.mailing_fax,
contact = self.object.group_contact,
physical_address_line_one = self.object.billing_address_line_one,
physical_address_line_two = "",
physical_city = self.object.billing_city,
physical_state = self.object.billing_state,
physical_zip_code = self.object.billing_zip_code,
physical_phone = self.object.billing_phone,
physical_fax = self.object.billing_fax,
)
gl.save()
new_grploc = gl
self.object.default_location_id = new_grploc.id
self.object.save()
new_group_id = self.object.id
new_grploc_id = new_grploc.id
### Now check the list of providers to see what has changed
print "group_add_provider: ",
print request.POST.getlist('group_add_provider')
add_providers = request.POST.getlist('group_add_provider')
if add_providers:
for pro in add_providers:
add_grploc = GroupLocationProvider(
grouplocation=GroupLocation.objects.get(pk=new_grploc_id),
provider=Provider.objects.get(pk=pro)
)
add_grploc.save()
### Now check the list of insurances to see what has changed
print "group_add_insurance: ",
print request.POST.getlist('group_add_insurance')
add_insurances = request.POST.getlist('group_add_insurance')
if add_insurances:
for ins in add_insurances:
add_grpins = GroupInsurance(
group=Group.objects.get(pk=new_group_id),
insurance=Insurance.objects.get(pk=ins)
)
add_grpins.save()
#return HttpResponseRedirect(self.get_success_url()) #how it used to work, just fine but would go back to my list of groups
return HttpResponseRedirect('ipaswdb:group_detail', self.object.pk) #want it to call my edit view here.
My Url Patterns
app_name = 'ipaswdb'
urlpatterns = [
url(r'^group/(?P<pk>[0-9]+)/$', GroupUpdateView.as_view(), name='group_detail'),
url(r'^group/add/$', GroupCreateView.as_view(), name='group_add'),
..etc..
Got an error but I feel I am closer?
DisallowedRedirect at /ipaswdb/group/add/
Unsafe redirect to URL with protocol 'ipaswdb'
I really want to load the page with the created object but as an updateview
Anyway to do this from the create view?
It is highly recommended to return a redirect request from a successful POST request. Otherwise a user might accidentally create multiple objects by reloading the page. Something like this:
from django.shortcuts import redirect
...
return redirect('name-of-update-url', pk=obj.pk)
If you really do not want to use a redirect, it is a bit more involved. Class based views are not meant to be called directly. The as_view method you use in your urls.py creates a wrapper function which instantiates the class and calls dispatch, which selects the right handler method (get/post/...). But you can't use as_view, because you have a POST request, but probably want to call the get method.
So you have to create an instance of your UpdateView and directly call its get method. With a standard UpdateView, can try something like this:
class GroupCreateView(CreateView):
...
def post(self, request, *args, **kwargs):
...
obj = ... # create your object
update_view = UpdateView()
update_view.request = self.request
update_view.args = []
update_view.kwargs = {'pk': obj.pk}
return update_view.get(self.request)
If you heavily customized your UpdateView, you might have to adapt this.
My go-to resource how Django's class-based views look under the hood is https://ccbv.co.uk