1

i want to call class based index view in function view i render the index template in login function view but when i add a extra context in index template which i do from function views ' it only render's extra context not the one which is already rendered by class based index view.

so i thought if i could call class based index view from function so that i add extra context to class based view and render it at the same time.

in short word's i want to add extra context from function view and render it.

this is my class based generic view for listing object's in index template.

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    title = 'hello'
    num_visit = 'a'
    context_object_name = 'question_list'

    def get_queryset(self):
        """Return the last five published questions."""
           return Question.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:5]

and this is my login view that render's the same template which class based index view does

def login_view(request):
    user = authenticate(request,username=request.POST['username'],password=request.POST['password'])
    if user is not None:
        login(request, user)
        return redirect('polls:index')
    return render_to_response('polls/index.html', {'error_message': 'wrong credentials'})

.................................................

now i can login in index template but the look at the code context adding does'nt workin maybe it work's but i think it does messes up with default object list context.

class IndexView(generic.ListView):
template_name = 'polls/index.html'
title = 'sdasd'
num_visit = 'a'
context_object_name = 'question_list'
error_message = None

def get_queryset(self):
    """Return the last five published questions."""
    return Question.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:5]

def post(self, request, **kwargs):
    user = authenticate(request, username=request.POST['username'], password=request.POST['password'])
    if user is not None:
        login(request, user)
        return redirect('polls:index')
    error_message = 'i love jesus'
    context = self.get_context_data(request, error_message, **kwargs)
    return render(request, 'polls:index', context)



def get_context_data(self, *args, **kwargs):
    context = super(IndexView, self).get_context_data(**kwargs)
    context['error_message'] = self.args
    return context

Template code .............. cant add the template code ' it's complicated i added here https://codeshare.io/5zXYJb

trackback error https://ibb.co/jdA7Ek

Andriken sonwane
  • 383
  • 1
  • 5
  • 14
  • Could you please post some code? – Thiago Rossener Jul 25 '17 at 16:55
  • 1
    You should never call one view from another view. If you have common code in two views, move it to a utility method outside of your views (create a utils.py file) or move it into the model. You should try to move as much logic as possible down towards your models. – Ian Kirkpatrick Jul 25 '17 at 17:03
  • @IanKirkpatrick i dont think there is another way ' because i want to add login page in same index page where there is also list view is used....... i dont want to use login view for different url in different template ' i hope you understand this is how i want to challenge my self. – Andriken sonwane Jul 25 '17 at 17:18
  • @IanKirkpatrick you mean login as an model's so that i can use in any views ? – Andriken sonwane Jul 25 '17 at 17:21
  • So you want a login section on your index page, not a seperate page dedicated just to login? Kind of like Amazons quick login on the top of every page? – Ian Kirkpatrick Jul 25 '17 at 17:26
  • @IanKirkpatrick yeah but it was my own idea of doing that ' i actually saw most of the website used to have separate login and i though how about login on index page and that is why when i render the index template with adding extra context it add's only from the login view and the index view list does'nt get rendered. – Andriken sonwane Jul 25 '17 at 17:39
  • I'm answering in an actual answer below... – Ian Kirkpatrick Jul 25 '17 at 17:44
  • @IanKirkpatrick i am actually a beginner it's jut 1 month i've been taking reference from djangoproject site ' utils.py file thing , sound like new thing's for me – Andriken sonwane Jul 25 '17 at 17:47
  • Oh... well it's pretty hard for me to explain this over keyboard as there's a lot of concepts that could go into this. IDK what knowledge you have so I tried my best to answer below. If you don't understand a part of my answer, comment and I'll try to clear things up. I love teaching programming concepts so don't be afraid to ask questions that sound stupid. There's no such thing as stupid questions – Ian Kirkpatrick Jul 25 '17 at 18:00
  • @IanKirkpatrick check now the code i added ' i hope you'll understand now. – Andriken sonwane Jul 25 '17 at 18:14
  • I just updated my answer – Ian Kirkpatrick Jul 25 '17 at 18:29

1 Answers1

1

You should not call logic from one view into another. Create a login logic. You didn't post any code so I'm not quite sure how your program works but you could do this:

In forms.py

class MyLoginForm(Form):
    username = forms.TextField(...)
    password = forms.PasswordField(...)

In utils.py

def login(request, user_name, password):
    user = authenticate(request, username=user_name, password=password)
    if user is not None:
        login(request, user)
        return True
    return False

def index_context(...):
    context = {}
    # do context stuff here
    return context

In views.py

class Index(View):
    def post(self, request, *args, **kwargs):
        # The logging_in part is optional but it's used to know when a post request is a login post or for something else. Just add a hidden field in your login form that has this name and a value of True.
        if request.POST.get("logging_in", False):
            authenticated = utils.login(request, request.POST.get("username", ""), request.POST.get("password", ""))

            if authenticated:
                # refresh the page
            else:
                # refresh the page with error
        else:
            # do other POST actions.

    def get(self, request, *args, **kwargs):
        # add a username and password form to context along with whatever other context you need.
        context = utils.index_context(...)
        context["login_form"] = MyLoginForm
        return render(request, "index.html", context)

def login_view(request):
    # Used if you also want a separate login page too.
    if request.method == "POST":
        loggedin = utils.login(request, request.POST.get("username", ""), request.POST.get("password", ""))
        if loggedin:
            return redirect('polls:login')
        return render_to_response('polls/login.html', {'error_message': 'wrong credentials'})
    else:
        # render template with username and password field
        context = {}
        context["login_form"] = MyLoginForm
        return render(request, "login.html", context)

You could also just have a API view that just does login stuff and have ajax call this view. Either way, the actual logic for logging in should be in a separate function that is global.

Ian Kirkpatrick
  • 1,861
  • 14
  • 33
  • even if i use your code it's look's like it's doing the same thing what my code does ........ how does it suppose to render the data from index view which is list of object's ....... what i wanted was to add extra context from my simple login view to generic list view and render both from login view so that both context will be render in index template at the same time. – Andriken sonwane Jul 25 '17 at 18:41
  • I just edited the answer. Note the new method in utils.py – Ian Kirkpatrick Jul 25 '17 at 18:48
  • i used post method in class based list view ' it's working fine but second thing i want to do with it is..... in my class based list view ' there are some object list which is rendered automatically by django , and the only way to add extra context is the using get_context_method. what i did was i used get context method in post method and added a new variable then i render and what error i got was 'IndexView' object has no attribute 'object_list' seem's like when i add extra context and render context in post method it throws error. – Andriken sonwane Jul 26 '17 at 11:30
  • Can I see your entire view? both views? – Ian Kirkpatrick Jul 26 '17 at 13:49
  • how do i add code here ? it wont let me add more than 15 character's – Andriken sonwane Jul 26 '17 at 15:12
  • Update your question – Ian Kirkpatrick Jul 26 '17 at 15:36
  • Did you try overriding get_context_data? you can add extra context through that method. get_context_data returns a dictionary where the keys are the variables used in the template. see https://stackoverflow.com/questions/8031890/how-do-you-use-get-context-data-with-templateview-in-django. In this example, they're using TemplateView but it will work with any View type. – Ian Kirkpatrick Jul 26 '17 at 17:13
  • the last thing i've done was exactly this ' i tried get context method and return the context ' no use of doing it seperately i want to use it in post method if/else condition. – Andriken sonwane Jul 26 '17 at 17:43
  • Send the if/else logic to the override of get_context_data. you can add variables to the method through *args and **kwargs. just make sure you pop yours out before you call the super get_context_data. in the get_context_data, if your variable is true, it can be assumed you're logging in. Or something to that effect. The actual heading of get_context_data is `def get_context_data(self, *args, **kwargs)` so use `*args`, and `**kwargs` to your advantage. – Ian Kirkpatrick Jul 26 '17 at 17:55
  • how should i call get_context_data to pass variable in it from post method , `context = self.get_context_data()` or `context = get_context_data()` – Andriken sonwane Jul 26 '17 at 18:08
  • I don't think the second one will even work. Python requires you use the self, I'm pretty sure. Even if it does though, its simply a matter of clarity. I'm a big fan of adding more wording/code for better clarity. I would user `self.get_context_data(*args, **kwargs)` To add avariable, call `context = `self.get_context_data(*args, logging_in=True, **kwargs)`. You may have to switch the logging_in keyword around in the parameters for syntax sake however. – Ian Kirkpatrick Jul 26 '17 at 19:36
  • i did but no luck tried different variation of adding context but no use..... the problem is with the post method i think there is no way adding context using post method ' because when i do it seperately it's get added but when i do it using post method it does'nt work. – Andriken sonwane Jul 27 '17 at 12:23
  • what do you mean by "do it using post"? – Ian Kirkpatrick Jul 27 '17 at 13:18
  • as you can see in my code i render index template in post method that's where i want to add context only on condition ...... by mean's i add context through post method. – Andriken sonwane Jul 27 '17 at 15:43
  • both get and post methods use get_context_data the same way. you render your template using `render(request, "mytemplate.html", context_dictionary)` context_dictionary can have anything in it but it must be a dictionary. There's no behind the scenes processing of get_context_data unless you don't override post or get. So what you have up top will work... just add whatever variables you want into your context dictionary (which you have named context). – Ian Kirkpatrick Jul 27 '17 at 15:50
  • dude ' i have tried in various way's , i know how to use them , i tried inside post method even had override the get_context method the got same error, it's seem's every possible way im doing right way to add context ' i get the same error check the photo [link]https://ibb.co/ns7vZk[link] – Andriken sonwane Jul 27 '17 at 16:24
  • Wait, why are you returning get_context_data in post? post uses get_context_data but get_context_data returns a dictionary. Post is suppost to return an HttpResponse object.That's what render is for. Then you pass context to render. – Ian Kirkpatrick Jul 27 '17 at 16:45
  • What was the outcome or error you got this time? Also, check this out: https://stackoverflow.com/questions/21371005/django-why-should-i-ever-use-the-render-to-response-at-all. Try specifying context_instance or use render. I prefer just using render. – Ian Kirkpatrick Jul 27 '17 at 17:14
  • you wont believe im getting same error ' i told you it seem's it close to the edge of adding context..... look at the error im getting since im adding context everytime ! `File "C:\Python27\lib\site-packages\django-1.11rc1-py2.7.egg\django\views\generic\list.py", line 130, in get_context_data queryset = kwargs.pop('object_list', self.object_list) AttributeError: 'IndexView' object has no attribute 'object_list' ` – Andriken sonwane Jul 27 '17 at 17:22
  • yeah i love to use his name in like every good thing i do ' may sound's ridiculous but he's programmer to i guess ! – Andriken sonwane Jul 27 '17 at 17:24
  • Ok, so I see a couple of things wrong in your code. Idk which one is throwing your error so I'll try to address them 1 by one and we'll eventually get to the bottom of this. Thanks for your patience in me not understanding your problem. first... Would you please post your template? and also the full traceback of the error. Do a screen shot of the traceback. I want to see where it's hitting. Also, the entire class based view. I know its a lot but I don't want to assume what your code does. – Ian Kirkpatrick Jul 27 '17 at 17:29
  • check i updated traceback error , template code and entire view .... will see you tommorow it's night night here ! – Andriken sonwane Jul 27 '17 at 18:04
  • Try adding `model = Question # or whatever model the list is of.` See https://docs.djangoproject.com/en/1.11/ref/class-based-views/generic-display/#listview – Ian Kirkpatrick Jul 27 '17 at 18:20
  • Also, the string you put in the render should be a file path to a template (e.g. "polls/indext_template.html"), not a url name. The "foo:bar" is what you use to point to a url. You want to render a template. not a url. – Ian Kirkpatrick Jul 27 '17 at 18:27