How to pass context to a different view function?(Django) - python

My models.py:
class fields(models.Model):
name = models.CharField(max_length=18)
link = models.TextField()
The link contains the hyperlink of the related name.
My views.py:
def index(request):
listing = fields.objects.all()
context ={'listing':'listing'}
return render(request,'index.html',context)
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('',index,name="index"),
]
template:
{% for i in listing %}
<tr>
<td data-label="name">{{ i.name }}</td>
<td data-label="Quote"><button>{{ i.link }}</button></td>
<tr>
{% endfor %}
This redirects to the hyperlink that is displayed in the template but I want to do some automation after it redirects into this link.
Now, I want to pass the context of this function which only includes the link to the other view function so that another view function will be:
def bypass_link(request):
# get the link from above function
# execute some selenium scripts in the link
The simple template to illustrate this will be:
{% for i in listing %}
<tr>
<td data-label="name">{{ i.name }}</td>
<td data-label="Quote"><button>{{ i.link }}</button></td>
<tr>
{% endfor %}

You can pass the id of the object into the url by altering the following:
template
<td data-label="Quote">
{{ i.link }}
</td>
urls.py
from django.conf.urls import url
url(r'^bypass_link/(?P<pk>\d+)/$', views.bypass_link, name="bypass_link"),
Then in your function you need to find the same model instance and then extract the link.
def bypass_link(request, pk=None):
instance = fields.objects.get(pk=pk)
print(instance.link) # now you have your link
Now you have access to the link via instance.link

You can pass variable to different views in Django using session
My example is using Django 3.2, be sure that sessions requirement are set in settings.py. But by the default config, the following example should work.
def index(request):
listing = fields.objects.all()
# The session object must be json serializable, pay attention
listing_list = [[list.name, list.i] for list in listing]
# set the session variable
request.session['listing_list'] = listing_list
context ={'listing':listing}
return render(request,'index.html',context)
def bypass_link(request):
# get the link from above function
# execute some selenium scripts in the link
# Got the session variable
listing_list = request.session.get('listing_list')
# Do what you want with it here

Related

Display all User profiles, in Django template, liked by the currently logged-in User (under ManytoMany field)

I built a portal, where members can see other users' profiles and can like them.
I want to show a page where the currently logged-in users can see a list of profiles only of the members they liked.
The Model has a filed 'liked', where those likes of each member profile are stored:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
company = models.CharField(max_length=500, blank = True)
city = models.CharField(max_length=100, blank = True)
website = models.URLField(max_length=500, blank = True)
liked = models.ManyToManyField(User, related_name='user_liked', blank=True)
My views.py, and here I only show all members so on my template I can loop through each member in members... Including 'member.profile' details from the Profile model.
#login_required
def all_fav_members(request):
users = User.objects.all
context = {'members':users}
return render(request, 'club/all_fav_members.html', context)
I've tried many things, both under views.py and my HTML template, but I was not able to loop through all users associated with a specific Profile under the 'liked' field where that user is equal to request.user.
I'm new to Django, hence trying multiple things. The outcome usually is I get the whole list of members, not the ones current user liked.
One of the not working examples:
{% if member.profile.liked.filter(id=request.user.id).exists()%}
My template:
{% for member in members %}
<table class="table w-100 table-hover">
<thead>
<tr id="header-paragraph-table-top">
<th>Name & Surname</th>
<th>Email</th>
<th>Company</th>
</tr>
</thead>
<tbody>
<tr id="paragraph-table">
<td>{{ member.first_name|capfirst }} {{ member.last_name|capfirst }}</td>
<td>{{ member.email }}</td>
<td>{{ member.profile.company }}</td>
</tr>
</tbody>
</table>
urls.py
path('all_fav_members/', views.all_fav_members, name='all_fav_members'),
I would probably use template tags to solve this issue.
Read this page to get to know how to register template tags: https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/
Inside your_template_tags:
from django import template
register = template.Library()
#register.filter
def liked_user(user, other_user):
return user.profile.liked.filter(id=other_user.id).exists()
Inside your template you could do the following:
{% load your_template_tags %}
{% if member|liked_user:request.user %}
Although I would probably handle it in the views.py like this:
for member in context["members"]:
member.liked_by_user = member.profile.liked.filter(id=request.user.profile.id).exists()
Then you could just use this property in your template like:
{% if member.liked_by_user %}

Django - Player URL not found despite being in urls.py

Over the last few days I have been working on building a Django web application for allowing users to make queries on a MLB Statistics database. I have some of the web app working fine, however I tried to implement a search function and ran into problems with the URL mapping. I tried to move on from this and instead work on getting the database to display information based on the link to the player that they click on, but I am running into the same issue with the URL's being dynamic based on the player's player_id. This portion only uses the People model which has player_id as its primary key.
Currently, I have an 'allPlayers.html' that lists every player in the database along with a link sending the player's player_id to the url as so:
allPlayers.html
{% extends "base_template.html" %}
{% block content %}
<h1>MLB Stats All Players</h1>
<p>Currently, there are : {{ num_players }} players listed in the database.</p>
<table style="width:100%">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th></th>
</tr>
{% for player in players %}
<tr>
<td>{{ player.name_first }}</td>
<td>{{ player.name_last }}</td>
<td>More on {{ player.name_first }} {{ player.name_last }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
And the corresponding view for 'allPlayers.html':
def allplayers(request):
"""View function for allPlayers page of site."""
# Generate counts of people object
num_players = People.objects.count()
players = People.objects.all()
context = {
'num_players': num_players,
'players': players,
}
# Render the HTML template allPlayers.html w/ data in context variable
return render(request, 'allPlayers.html', context=context)
With just the above I have successfully created a page on my web app that lists each player in the database along with a link, and notice that I am trying to send the player_id through <a href='players/{{ player.player_id }}>. Currently the allPlayers portion works fine. However, things go south when I add the following playerInfo.html and corresponding view:
playerInfo.html
{% extends "base_template.html" %}
{% block content %}
{% if results %}
{% for player in results %}
<p>{{ player.name_first }} {{ player.name_last }}</p>
{% endfor %}
{% endif %}
{% endblock %}
And the view:
def player(request, pk=None):
if pk is not None:
print('Hello world')
print('pk :', pk)
#instance = get_object_or_404(People, player_id=pk)
results = People.object.filter(player_id=pk)
context = {
"results": results
}
return render(request, "playerInfo.html", context)
else:
print('Hello')
return render(request, 'playerInfo.html')
My idea was that the link noted earlier containing {{ player.player_id }} would match up with the following url and place the player_id value in for pk, as follows using the <int:pk> syntax instead of regex:
polls/urls.py
urlpatterns = [
path('', views.index, name='index'),
path('allPlayers', views.allplayers, name='allplayers'),
path('allTeams', views.allteams, name='allteams'),
path('search/', views.search, name='search'),
path('player/<int:pk>/', views.player, name='player'),
]
However, once I navigate to my 'allPlayers' page and click on one of the links for the player, say Hank Aaron (who has player_id aaronha01), I get the following Page not found (404) error:
Using the URLconf defined in baseballdb.urls, Django tried these URL patterns, in this order:
polls/ [name='index']
polls/ allPlayers [name='allplayers']
polls/ allTeams [name='allteams']
polls/ search/ [name='search']
polls/ player/<int:pk>/ [name='player']
admin/
The current path, polls/player/aaronha01/, didn't match any of these.
I have been having trouble with this for quite a bit now. If anyone has any advice and can point me in the right direction of how I'm thinking about this incorrectly or has a solution for me that would be seriously greatly appreciated! Thank you.
path('player/<int:pk>/' means only valid int pk would match. If your pk is not int and something like a valid slug - use path('player/<slug:pk>/' instead.
docs: https://docs.djangoproject.com/en/2.1/topics/http/urls/#path-converters
And my suggestion is to use {{ player.get_absolute_url }} or {% url 'player' player.id %} instead of building url manually.
Missing leading slash means "from here", not from website root:
https://webmasters.stackexchange.com/questions/56840/what-is-the-purpose-of-leading-slash-in-html-urls
There is a mismatch between <int:pk> in your path(), which expects an integer, and your player_id, which is a string like 'aaronha01'.
You can either use the pk everywhere, and have urls like /player/17/:
path('player/<int:pk>/', views.player, name='player'),
def player(request, pk):
instance = get_object_or_404(People, pk=pk)
context = {
"instance": instance,
}
return render(request, "playerInfo.html", context)
# Use pk in template when constructing URL
<td>More on {{ player.name_first }} {{ player.name_last }}</td>
Or you can use player_id everywhere, and have urls like /player/aaronha01/.
path('player/<slug:player_id>/', views.player, name='player'),
def player(request, player_id):
instance = get_object_or_404(People, player_id=player_id)
context = {
"instance": instance,
}
return render(request, "playerInfo.html", context)
# Use player_id in template when constructing URL
<td>More on {{ player.name_first }} {{ player.name_last }}</td>
As a next improvement, you can start using the {% url %} tag so that you aren't hardcoding the URLs anymore.
<a href="{% url "polls:player" player.player_id %}">
In the above, I've assumed that you have app_name='polls' in your polls/urls.py, and that you have decided to use player_id instead of pk in your url pattern.

Django 1.11 queries not working

I'm trying to set up something using Django 1.11 and python for my job where it will display a list of projects submitted by the logged in user. The user can click on the Project name and it will take the user to that project to edit it if they need to. I have it showing the list of projects but when the user clicks the name I get an error. It works fine when there is only 1 project displaying for that users. The error and my code is below.
MultipleObjectsReturned at /edit/
get() returned more than one Project -- it returned 2!
Request Method: GET
Request URL: http://127.0.0.1:8000/edit/
Django Version: 1.11
Exception Type: MultipleObjectsReturned
Exception Value:
get() returned more than one Project -- it returned 2!
url.py
urlpatterns = [
url(r'^index/',views.Index.as_view(),name='index'),
url(r'^form/', views.Form.as_view(), name = 'form'),
url(r'^edit/', views.EditProject.as_view(), name = 'editProject'),
]
views.py
class Index(LoginRequiredMixin,ListView):
template_name = 'sitename/index.html'
form_class = IndexForm
def get_queryset(self):
return Project.objects.filter(user=self.request.user)
class EditProject(LoginRequiredMixin, UpdateView):
template_name = 'irbSite/form.html'
form_class = ProjectForm
success_url = reverse_lazy('irbSite:index')
# works only when there is 1 project object
def get_object(self):
return Project.objects.get(user=self.request.user)
index.html
{% if user.is_authenticated %}
{% if project_list %}
<tr>
<th>Project Number</th>
<th>Project Name</th>
<th>Is Complete</th>
<th>Is Approved</th>
</tr>
{% for project in project_list %}
<tr>
<td><a href="{% url 'irbSite:editProject'%}">{{project.project_id}}</td>
<td>{{project.project_name}}</a></td>
<td>{{project.is_complete}}</td>
<td>{{project.is_approved}}</td>
{% endfor %}
</tr>
{% else %}
<p>You dont have any current IRB forms. Select "Submit New Project" on the left to start one.<p>
use .filter to get multiple object while querying.
Ex:
def get_object(self):
return Project.objects.filter(user=self.request.user)

Django button in Modelclass

I'm making an inventory app in which I could update the values of the products from my 'home.html'.
My proj name is Inventory
App name is myapp
Problem I am facing is that every time I update the value of a Stock from my homepage, it adds a new Product instead of updating the one that I want!
I am using the ModelsForm Class provided by Django.
Using Django=1.11 and Python=3.6
My project's urls.py:
from django.conf.urls import url,include
from django.contrib import admin
from myapp.views import home
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^myapp/', include('myapp.urls', namespace="myapp")),
url(r'^myapp/home/', home, name='home'),
]
My forms.py:
from django import forms
from .models import Inventory
class Operations(forms.ModelForm):
class Meta:
model = Inventory
fields = ('stocks_left',)
My app's Model.py:
from django.db import models
import uuid
class Inventory(models.Model):
"""
Model representing a the inventory.
"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
inventory_name = models.CharField("INVENTORY NAME" ,max_length=200, help_text="This contains the Inventory name:")
short_name = models.CharField(max_length=20, help_text="This contains an abbreviation:")
inventory_code = models.IntegerField("INVENTORY CODE" ,default = '0', help_text="This contains the Inventory code:")
price = models.IntegerField(default = '0')
stocks_left = models.IntegerField("STOCKS LEFT",default = '0')
def __str__(self):
"""
String for representing the Model object (in Admin site etc.)
"""
return '{0} ({1}) ({2})'.format(self.inventory_name,self.inventory_code,self.stocks_left)
My app's urls.py
from django.conf.urls import url
from . import views
from django.contrib.auth.views import login
app_name= 'myapp'
urlpatterns = [
url(r'^$', login, {'template_name': 'myapp/login.html'}),
]
and my views.py
from django.shortcuts import render,redirect
from django.contrib import auth
from django.contrib.auth.models import User
from django.views import generic
from django.http import HttpResponse
from myapp.models import Inventory
from .forms import Operations
def home(request):
names = Inventory.objects.all()
if request.method == "POST":
form = Operations(request.POST)
if form.is_valid():
stocks_left = form.save(commit=False)
stocks_left.save()
return redirect('myapp/home.html')
else:
form = Operations()
return render(request, 'myapp/home.html', { "names": names, "form": form})
and my home.html template:
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<title>Inventory</title>
</head>
<body>
<h1>Welcome!</h1>
<div class="container">
<table border="5" cellpadding="10" width="1000">
<thead align="center">
<tr>
<th align="center">#</th>
<th align="center">Name</th>
<th align="center">Inventory Code</th>
<th align="center">Stocks left</th>
<th align="center">Operations</th>
</tr>
<tr>
{% for x in names %}
<td align="center"> {{ x }}</td>
<td align="center"> {{ x.inventory_name }}</td>
<td align="center"> {{ x.inventory_code }}</td>
<td align="center"> {{ x.stocks_left }}</td>
<td><form method="POST">{% csrf_token %}{{form}}<button type="button" class="btn btn-primary"><span class="glyphicon glyphicon-plus"></span></button></form><br></td>
</tr>
{% endfor %}
</table>
</div>
</body>
Here is what you can do,
Create 2 fields in forms,
class Operations(forms.ModelForm):
class Meta:
model = Inventory
fields = ('stocks_left','inventory_name')
When you get the data in the view,
if request.method == "POST":
form = Operations(request.POST)
if form.is_valid():
inv_obj = form.cleaned_data.get('inventory_name')
inv_model_obj = Inventory.objects.get(inventory_name=inv_obj) #make sure to declare in the models that this inventory_name is unique
inv_model_obj.stocks_left = form.cleaned_data.get('stocks_left')
inv_model_obj.save()
return redirect('myapp/home.html')
If you do not pass instance=the_instance_you_want_to_edit to a ModelForm it will create a new instance. How else would the ModelForm know what model instance you mean to edit?
BaseModelForm.init
if instance is None:
# if we didn't get an instance, instantiate a new one
self.instance = opts.model()
object_data = {}
else:
self.instance = instance
object_data = model_to_dict(instance, opts.fields, opts.exclude)
Anyway, it is not really going to work well if you want to keep it all on one page. Either you manually type in the object_id to pass to the ModelForm later. Or you create a FormSet with each Form representing an Inventory object plus an input field for 'stocks_left'.
The former is a bit iffy because if you mistype the primary key you are going to change the stock of the wrong Inventory without noticing (or throw a DoesNotExist error down the road).
And the latter is total overkill if you only want to change a single Inventory.
You have two options and either option requires another page/template.
One page displays your overview and the other serves to update an Inventory's stock. The overview contains links to the individual update pages.
Capture the primary key of the object you want to edit from the url.
url(r'^myapp/home/([0-9]+)/$)', home, name='home-update')
The URL dispatcher will then call your home view function with the request and the captured parameter and you can instantiate the ModelForm with it.
def home(request, pk):
names = Inventory.objects.all()
if request.method == "POST":
form = Operations(request.POST, instance=Inventory.objects.get(pk=pk)
if form.is_valid():
form.save()
return redirect('myapp/home.html')
else:
form = Operations()
return render(request, 'myapp/a_very_basic_template_to_display_a_form.html', {"form": form})
Or use a class based UpdateView (for your 'update' page):
class InventoryStockUpdateView(views.generic.UpdateView):
model = Inventory
template_name = 'myapp/a_very_basic_template_to_display_a_form.html'
fields = ['stocks_left']
success_url = reverse_lazy('home')
With this in urls.py:
url(r'^myapp/home/(?P<pk>[0-9]+)/$)', InventoryStockUpdateView.as_view(), name='home-update')
To edit Inventory with the primary key 31415 you would then type '...home/31415' into your browser.
UPDATE:
Have you had a look at django's admin actions? They let you edit instances from the changelist by selecting them via a checkbox and then running an admin action on them. While that may not be quite what you want, investigating how exactly they work should teach you some tricks that would help you in your current task.
To maybe give you a few pointers on how to proceed: add <a> tags to your template, two (+/-) for every 'row' of instances you are displaying.
The href attribute of each tag of a should contain the row's instance and the element's 'job' (adding or subtracting a stock). These two values will be used in the url conf much like I described above...
As to how you properly build the href attribute; the template tag docs should help.
Maybe like so:
<tr>
{% for x in names %}
<td align="center"> {{ x }}</td>
<td align="center"> {{ x.inventory_name }}</td>
<td align="center"> {{ x.inventory_code }}</td>
<td align="center"> {{ x.stocks_left }}</td>
<td><a href={% url ??? %}>click me to subtract!</a></td>
<td><a href={% url ??? %}>click me to add!</a></td>
</tr>
{% endfor %}
Of course, you would also need a new view function to handle those urls, but those shouldn't be very difficult to figure out.

how do you change a database filter based on a link you click in django?

I would like to click on a link from my Django page and based on the link i clicked display a new database query filter from that name on the list
<tr>
<th>RootGroup List</th>
</tr>
{% for status in root %}
<tr>
<td><a href={{status.rootgroup }}> {{ status.rootgroup }} </a></td>
#I WANT TO CLICK THE LINK AND DISPLAY A NEW DATABASE BASED ON THE NAME WITH A FILTER OF THE NAME
</tr>
{% endfor %}
def display(request):
x = re.search('d.*','% url ''detail'' poll.id %')
rootFilter = Viewroot.objects.filter(rootstatus__gt=0, type = 1, ("LINK NAME")).values('rootgroup').distinct() #RootGroup List
#return render_to_response('status/index.html', { 'root' : rootFilter },context_instance=RequestContext(request))
#return HttpResponse( x.group(0)),render_to_response('status/index.html', {'app' : appFilter})
return HttpResponse("You displayed ", j )`
Basically, you can make this work by using named groups in your urls.py patterns, e.g.:
(r'^links/(?P<value>\w+)/$', display)
Then, you can access saved part of url inside your view, like:
def display(request, value=None):
print value
And, of course, you should use appropriate url in the template:
<td> {{ status.rootgroup }} </td>
Also see documentation.

Categories