how to get() this model that belongs to userprofile.team - python

I'm struggling getting this view to work. In the code I have included a comment that indicated where the issue is. Basically I can not for the life of me get the TeamsWeeklyMasterSchedule object that relates to the EmployeeProfile.team
Models
class Team(models.Model):
name = models.CharField(max_length=10)
def __str__(self):
"""Return a string representation of the model."""
return self.name
class TeamsWeeklyMasterSchedule(models.Model):
"""Hours Available For That Day"""
team = models.ForeignKey(Team, on_delete=models.CASCADE)
class EmloyeeProfile(models.Model):
owner = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, )
team = models.ForeignKey(Team, on_delete=models.CASCADE,)
View
#login_required
def employee(request):
"""The home page"""
profile = EmployeeProfile.objects.filter(owner=request.user)
# I Cannot make this get() work!
teams_weekly_master_schedule = TeamsWeeklyMasterSchedule.objects.get()
context = {
'profile': profile,
'teams_weekly_master_schedule': teams_weekly_master_schedule,
}
return render(request, 'portal/employee.html', context)
What I've Tried
teams_weekly_master_schedule = TeamsWeeklyMasterSchedule.objects.get(team=profile.team)
teams_weekly_master_schedule = TeamsWeeklyMasterSchedule.objects.get(team=request.user.team)

I was able to replicate the problem and I solved it with this:
def employee(request):
"""The home page"""
profile = EmployeeProfile.objects.get(owner=request.user)
teams_weekly_master_schedule = TeamsWeeklyMasterSchedule.objects.get(team = profile.team)
context = {
'profile': profile,
'teams_weekly_master_schedule': teams_weekly_master_schedule,
}
return render(request, 'test.html', context)
The first problem was that on line 3, you used filter to retrieve one EmployeeProfile object. Using filter returns a queryset, which can't be accessed as an object.
When you use GET, you can use profile.team which returns the team you want.

Related

Incorrect Context Appearing in Django Project

I am creating a workout project where for every workout there is a list of exercises and for every exercise there is a list of sets which has specific weights and reps.
Here is the model for more clarification:
class Workout(models.Model):
name = models.CharField(max_length = 30,blank=True, null=True)
date = models.DateField(blank=True, null=True)
def __str__(self):
return str(self.date) + ' ' + self.name
class Exercise(models.Model):
training = models.ForeignKey(Workout, on_delete=models.CASCADE, related_name='exercises',blank=True, null=True)
name = models.CharField(max_length = 30, blank=True, null=True)
def __str__(self):
return self.name
class Set(models.Model):
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE, related_name='sets',blank=True, null=True)
weight = models.FloatField(validators=[MinValueValidator(0)],blank=True, null=True)
repetitions = models.IntegerField(validators=[MinValueValidator(1)],blank=True, null=True)
order = models.IntegerField(validators=[MinValueValidator(1)],blank=True, null=True)
def __str__(self):
return self.exercise.name + ' set #' + str(self.order)
I am trying to show the list of rep in each set for a specific excercise in the template page but I keep getting errors such as:
activity() missing 1 required positional argument: 'request'
or even nothing is showing at all. The most recent view I coded shows all the sets for all the excercises which is not the objective.
Here is the views:
def activity(self,request, **kwargs):
template_name = 'my_gym/start_workout.html'
excercises = Exercise.objects.all().order_by('id')
sets = Set.objects.filter(
set=self.object).order_by('id')
context = {
'excercises': excercises,
'sets': sets,
}
return render(request, template_name, context)
I also tried:
def activity(request):
template_name = 'my_gym/start_workout.html'
excercises = Exercise.objects.all().order_by('id')
sets = Set.objects.all().order_by('id')
context = {
'excercises': excercises,
'sets': sets,
}
return render(request, template_name, context)
Here is also another trial using filter:
def activity(request):
template_name = 'my_gym/start_workout.html'
excercises = Exercise.objects.all().order_by('id')
sets = Set.objects.filter(sets=set.excercises).order_by('id')
context = {
'excercises': excercises,
'sets': sets,
}
return render(request, template_name, context)
I got this error:
type object 'set' has no attribute 'excercises'
Here is the template:
{% for set in sets %}
<td>{{set.order}}</td>
<td>{{set.repetitions}}</td>
{% endfor %}
My question is how to show the sets only for the selected excercise.
A more info there is a previous page which shows all th excercises and when one specific exercise is selected I am expecting to see the reps related to this specific excercise only not the reps for all the exercises in the database.
Thank you
As I did in my project(it was blog):
In urls.py I created new page with category_id(=Category primary key) like this:
path('category/<int:category_id>/', get_category, name='category')
Now in get_category function I get additional parameter that meant the pk of the category to which it belongs. And in views.py:
def get_category(request, category_id):
records = Recordings.objects.filter(category=category_id)
category = Category.objects.get(pk=category_id)
context = {
'records': records,
'category': category,
'title': category.title,
}
return render(request=request, template_name='blog/category.html', context=context)
I just filtered them by category.pk and it worked fine
In your case Recording = Set, Category = Exercise, category_id = exercise_id
Or if you use another way of creating pages for exercised - pls comment, it will be interesting to find a solution for such a model
P.S. This is early version of my project, there should be used select_related for request optimizing
P.P.S Optimized version of view + urls
# urls.py
path('category/<int:category_id>/', RecordingsByCategory.as_view(), name='category')
# views.py
class RecordingsByCategory(ListView):
model = Recordings
template_name = 'blog/category.html'
context_object_name = 'records'
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = Category.objects.get(pk=self.kwargs['category_id'])
return context
def get_queryset(self):
# kwargs goes from urls.py
return Recordings.objects.select_related('category').filter(category=self.kwargs['category_id'], is_published=True)

Can't handle two modelforms in a single submit/view flow with a FK relation?

I have the below two models
# models.py
class Applicant(models.Model):
"""
A table to store all applicants, relates 1-n to an offer
"""
name = models.CharField(max_length=50)
job = models.CharField(max_length=50)
start = models.DateField(null=True, blank=True)
def __str__(self):
return f'{self.name} applying for {self.job} starting {self.start}'
class Offer(models.Model):
"""
A table to store created offers
"""
# Relations
applicant = models.ForeignKey(Applicant, on_delete=models.CASCADE)
# Self
monthly_raise = models.FloatField()
months = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(60)])
start_salary = models.FloatField()
In my template I render all fields except for start (which I don't render at all) in the same <form></form> wrapper. Now in my view I want to create new instances for each of the modelforms but only if both are valid.
This is what I have which throws
NOT NULL constraint failed: planner_offer.applicant_id
def render_dashboard_planner(request):
site = 'planner'
if request.method == 'GET':
applicant_form = ApplicantForm()
offer_form = OfferForm()
context = {
'applicant_form': applicant_form,
'offer_form': offer_form,
'site': site
}
return render(request, "dashboard/dashboard_planner.html", context)
else:
# Process the created Offer
applicant_form = ApplicantForm()
offer_form = OfferForm()
form_applicant = ApplicantForm(request.POST)
form_offer = OfferForm(request.POST)
if form_applicant.is_valid() and form_offer.is_valid():
# Grab the data
form_applicant.save(commit=True)
# Create Offer instance
form_offer.save(commit=False)
form_offer.applicant = form_applicant
form_offer.save(commit=True)
context = {
'site': site,
'offer_form': offer_form,
'applicant_form': applicant_form,
}
return render(request, "dashboard/dashboard_planner.html", context)
How would I fix the relation issue and is this a proper way to handle the workflow in that manner at all?
You should set the .applicant on the .instance of the form, and use the instance of the form_applicant, not the form_applicant itself, so:
from django.shortcuts import redirect
def render_dashboard_planner(request):
site = 'planner'
if request.method == 'POST':
form_applicant = ApplicantForm(request.POST, request.FILES)
form_offer = OfferForm(request.POST, request.FILES)
if form_applicant.is_valid() and form_offer.is_valid():
# Grab the data
applicant = form_applicant.save()
form_offer.instance.applicant = applicant
form_offer.save()
return redirect('name-of-some-view')
else:
applicant_form = ApplicantForm()
offer_form = OfferForm()
context = {
'applicant_form': applicant_form,
'offer_form': offer_form,
'site': site
}
return render(request, 'dashboard/dashboard_planner.html', context)

How do i query model managers in my function based views for single_page(detail.html)

I'm finding it difficult to query a custom django model manager in my function based detail view. How can i resolve this?
I'm using django 2.2.
in my models.py file, i have this code below, which works perfectly. Querying for the listview is working fine and when i query the detail view using get_object_or_404(Modelname, id), the detail views works too but when i try to query it using my custom model manager, i keep getting this error
"movie_detail() got an unexpected keyword argument 'id'".
i've also tried removing--->
def get_absolute_url(self):
return reverse('core:movie_detail', args=[self.id,])
from my movie model when querying the model manager, but am still get same error
How can i resolve this?
my models.py
class MovieManager(models.Manager):
def all_with_related_persons(self):
qs = self.get_queryset()
qs = qs.select_related('director')
qs = qs.prefetch_related('writers', 'actors')
return qs
class Movie(models.Model):
NOT_RATED = 0
RATED_G = 1
RATED_PG = 2
RATED_R = 3
RATINGS = (
(NOT_RATED, 'NR - Not Rated'),
(RATED_G, 'G - General Audiences'),
(RATED_PG, ' PG - Parental Guidance' 'Suggested'),
(RATED_R, 'R - Restricted'),
)
title = models.CharField(max_length=140)
plot = models.TextField()
year = models.PositiveIntegerField()
rating = models.IntegerField(choices=RATINGS, default=NOT_RATED)
runtime = models.PositiveIntegerField()
website = models.URLField(blank=True)
director = models.ForeignKey(to='Person',
on_delete=models.SET_NULL,
related_name="directed",
null=True,
blank=True)
writer = models.ManyToManyField(to="Person", related_name="writing_credits", blank=True)
actors = models.ManyToManyField(to="Person", through="Role", related_name="acting_credits", blank=True)
objects = MovieManager()
def __str__(self):
return '{} ({})'.format(self.title, self.year)
def get_absolute_url(self):
return reverse('core:movie_detail', args=[self.id,])
class Meta:
ordering = ('-year', 'title',)
<--- Views.py --->
My List view
def movie_list(request):
object_list = Movie.objects.all()
paginator = Paginator(object_list, 12)
page_number = request.GET.get('page', 1)
try:
page = paginator.page(page_number)
except PageNotAnInteger:
# If page is not an integer deliver the first page
page = paginator.page(1)
except EmptyPage:
# If page is out of range deliver last page of results
page = paginator.page(paginator.num_pages)
context = {
'object_list': object_list,
'products': page,
'page': page,
}
template = 'core/movie_list.html'
return render(request, template, context)
DetailView without custom model manager.(This works)
def movie_detail(request, id):
object_list = get_object_or_404(Person, id=id)
context = {'movie': object_list}
template = 'core/person_detail.html'
return render(request, template, context)
DetailView with custom model manager.(This doesn't work. throws an error "movie_detail() got an unexpected keyword argument 'id'")
def movie_detail(request):
object_list = Movie.objects.all_with_related_persons()
context = {'movie': object_list}
template = 'core/movie_detail.html'
return render(request, template, context)
My url path to the detail_view
path('<id>/', views.movie_detail, name="movie_detail"),
I expect detail view to return queries based on what i queried in my custom model manager.
Your url pattern for the movie_detail view is passing an id kwarg to your view, so your view needs to accept this id as argument. Instead of
def movie_detail(request)
you should define
def movie_detail(request, id)
The error you see just says: movie_detail was called with keyword argument id, meaning it was called like this: movie_detail(request=the_request, id=some_id) which can't work if it's defined to only have one argument, request.
But also, since you're making a detail view for one object, you should probably do something with the id to select the specific object:
def movie_detail(request, id):
object_list = Movie.objects.all_with_related_persons()
try:
movie = object_list.get(id=id)
except Movie.DoesNotExist:
raise Http404
context = {'movie': movie}
template = 'core/movie_detail.html'
return render(request, template, context)

Django session passes argument from a view to another but sets the same value for all user instances

I am passing an (is_followed) parameter from one class based view FollowToggleAPIView to another UserDetailAPIVIew. I do this using Django session (from reading other thread on this platform) in the hope of displaying the follow-status (True or False) of the user_to_toggle variable on the UserSingleProfileSerializer.
Here are my views:
class UserDetailAPIVIew(generics.RetrieveAPIView):
'''
Displays a list of a user's posts
'''
serializer_class = UserSingleProfileSerializer
queryset = User.objects.all()
def get_object(self):
self.object = get_object_or_404(User,
username__iexact=self.kwargs.get('username')
)
return self.object
def get_serializer_context(self):
'''
passing the extra is_following argument to the UserDetailAPIVIew
'''
context = super(UserDetailAPIVIew, self).get_serializer_context()
is_followed = self.request.session.get('followed')
context.update({'followed': is_followed})
return context
class FollowToggleAPIView(APIView):
'''
Uses the custom model manager for user toggle follow
'''
def get(self, request, username, format=None):
user_to_toggle = get_object_or_404(User, username__iexact=username)
me = request.user
message = 'Not allowed'
if request.user.is_authenticated():
is_followed = UserProfile.objects.toggle_follow(me, user_to_toggle)
request.session['followed'] = is_followed
return Response({'followed': is_followed})
return Response({'message': message}, status=400)
The toggle_follow method is defined in the custom model manager as follows:
class UserProfileManager(models.Manager):
def toggle_follow(self, user, to_toggle_user):
''' follow unfollow users '''
user_profile, created = UserProfile.objects.get_or_create(user=user)
if to_toggle_user in user_profile.following.all():
user_profile.following.remove(to_toggle_user)
added = False
else:
user_profile.following.add(to_toggle_user)
added = True
return added
class UserProfile(models.Model):
'''
Extends the Django User model
'''
user = models.OneToOneField(settings.AUTH_USER_MODEL,
related_name='profile')
following = models.ManyToManyField(settings.AUTH_USER_MODEL,
blank=True,
related_name='followed_by')
objects = UserProfileManager()
def get_absolute_url(self):
return reverse_lazy('profiles:detail',
kwargs={'username':self.user.username})
def __str__(self):
return 'Username: {} [ Followers ({});
Following({})]'.format(self.user.username,
self.user.followed_by.all().count(),
self.following.all().count())
The urls.py:
urlpatterns = [
url(r'^(?P<username>[\w.#+-]+)/$', UserDetailAPIVIew.as_view(),
name='user-posts-api'),
url(r'^(?P<username>[\w.#+-]+)/follow/$',
FollowToggleAPIView.as_view(), name='follow-api'),
]
The only problem is that the value of (is_followed) displayed in UserSingleProfileSerializer is set for all user instances at once (not for the specific user we want to follow).
I am certainly not following/unfollowing all users at the same time (since the FollowToggleAPIView targets a specific user by his username).
I want to know how can I transfer the value of (is_followed) only to the specific user (user_to_toggle) in the UserDetailAPIVIew. Thank you in advance.
The session is completely the wrong thing to use here. You're storing a single "followed" value which only records the last user they toggled and has no relation to the profile they're actually viewing.
Instead of doing this, you should simply query in the UserDetailAPIVIew the followed status of the specific user.
def get_serializer_context(self):
context = super(UserDetailAPIVIew, self).get_serializer_context()
is_followed = self.request.user.profile.following.filter(username=self.object).exists()
context.update({'followed': is_followed})
return context
Note also, your toggle method is itself very inefficient - there's no need to retrieve every follow from the database just to check whether the current user is among them. Use exists again:
user_profile, created = UserProfile.objects.get_or_create(user=user)
if user_profile.following.filter(username=to_toggle_user).exists():

getting the id from a foreignkey relationship django

I want to get the id or pk of a ForeignKey relationship post_comment but I've tried many different ways to catch it and i do not have any good result, please guys give me a hand in this situation
In views.py
class createComment(View):
form_class = CommentForm
template_name = "createComment.html"
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form':form})
def post(self, request):
obj = self.form_class(None)
obj.title_comment = self.request.POST['title_comment']
obj.body_comment = self.request.POST['body_comment']
obj.post_comment = self.pk
obj.save()
In models.py
class Comment(models.Model):
user_comment = models.ForeignKey("auth.User")
title_comment = models.CharField(max_length=50)
body_comment = models.TextField()
timestamp_comment = models.DateTimeField(auto_now=True)
post_comment = models.ForeignKey("Post", null=True)
status_comment = models.BooleanField(default=True)
def __unicode__(self):
return unicode(self.title_comment)
def __str__(self):
return self.title_comment
You can pass a primary key in the url, and then use it in your class as one way.
kwargs.get(pk name)
You could change post to:
def post(self, request, *args, **kwargs)
You then can't just assign obj.post_comment = kwargs.get(pk) you have to actually get the object.
Post.objects.get(pk = pk)
You might want to also consider renaming fieldname_comment to just fieldname for your models fields. Seems a bit redundant to have _comment on every single field in the Comment model.
I don't know how works class based views but I can tell you that self.pk does not exist in class based view, you would try get form instance and get the I'd field from this instance...

Categories