if-else statement in python django - python

I am new to Django and I have a problem that I couldn't solve. I am trying to display a specific question and other related attribute from my Question model based on a field from the Participant model. The issue here is that it directly goes to the else statement even when the condition is true.I tried to print(participant.condition) and it works so I am not sure why its not working with the if statement.
#login_required
def LPSC_VIEW1(request):
participant=request.user.participant
if participant.condition == 'LPN':
First_question= Question.objects.get(id=1)
all_choices = First_question.choices.all()
context = {'First_question': First_question, 'all_choices': all_choices}
return render(request, 'study/FirstQN.html', context)
else:
First_question= Question.objects.get(id=12)
all_choices = First_question.choices.all()
context = {'First_question': First_question, 'all_choices': all_choices}
return render(request, 'study/FirstQSC.html', context)
my models as the following:
class Question(models.Model):
question_text = models.CharField(max_length=200)
caption = models.CharField(max_length=200, default="this is a caption")
choices = models.ManyToManyField(Choice)
vis_image = models.ImageField(default= "this is an image", null=False, blank=False, upload_to="static/study/img")
def __str__(self):
return self.question_text
class Condition(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Participant(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
condition = models.ForeignKey(Condition, on_delete=models.CASCADE)
score = models.IntegerField(default=0)
def __str__(self):
return self.user.username

condition is a foreign key, not a string. You're comparing it against 'LPN', but no instance of your Condition model will be equal to that string.
Try if participant.condition.name == 'LPN': to compare the name field on the Condition instance to that string.
Your print statement shows them as apparently being the same because you've defined how to present Condition instances as strings with your __str__ method - it will print the name for the Condition instance, but that doesn't mean that the Condition value is actually equal to that string.

You must change this:
participant=request.user.participant
to:
participant=Participant.objects.get(user=request.user)

You might have to use
from .models import Participant
participant = Participant.objects.get(user = request.user)

Related

Filtering Forms in Django

I am making a small project to rate salesmen. I have regions and each region has its salesmen. So, if region "blahblah" is selected, form should show salesmen choices which are related to that region. I have found some answers via stackoverflow, but it still shows all salesmen, regardless of their regions.
My model is this:
class Region(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True)
def __str__(self):
return self.name
class Salesman(models.Model):
region = models.ForeignKey(Region,
related_name='region',
on_delete=models.CASCADE)
name = models.CharField(max_length=40)
surname = models.CharField(max_length=40)
def __str__(self):
return self.name
class Rating(models.Model):
RATING_CHOICES = [(i, str(i)) for i in range(1,6)]
salesman = models.ForeignKey(Salesman,
related_name='salesman',
on_delete=models.CASCADE)
phone = models.CharField(max_length=15, blank=True)
rating = models.IntegerField(choices=RATING_CHOICES, blank=False)
sent_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.phone
I found modified __init__ method for my forms.py:
class RateAddForm(forms.ModelForm):
class Meta:
model = Rating
def __init__(self, region_id=None, **kwargs):
super(RateAddForm, self).__init__(**kwargs)
if region_id:
self.fields['salesman'].queryset = Salesman.objects.filter(region=region_id)
And also my views.py is this:
def report_add(request, region_id):
if request.method == 'POST':
print(region_id)
form = RateAddForm(request.POST, region_id=region_id)
if form.is_valid():
message = "Thanks!"
form.save()
return HttpResponse(message)
else:
print("Something went wrong!")
form = RateAddForm()
else:
form = RateAddForm(request.POST)
return render(request,
'account/report.html',
{'form': form})
It still shows me all salesmen on my database, even if i choose a region. How to solve this problem that form should show only salesmen of selected region. Thanks in advance!
Try setting the self.base_fields['salesman'].queryset instead of
self.fields['salesman'].queryset (i.e "base_fields" instead of "fields").
(That's what I do when I need to filter in Admin forms)

Add an exception for model relationship of a specific object

I am kind a newbie in django and python. In my app each user is assigned many projects but each project has a specific user. What I am trying to achieve is to show to a user that never created any project, a project demo.
I tried that when a user register he is directly assigned the demo project but since a project can have only one user is does not work when another sign in..
Is it possible to create an exception to a model attribute et to specify that for a specific Project can have multiple users ?
Here is my code:
Project model :
class Project(models.Model):
name = models.CharField(max_length=250)
team_id = models.ForeignKey(Team, blank=True, null=True)
project_hr_admin = models.ForeignKey('registration.MyUser', blank=True, null=True)
candidat_answers = models.ManyToManyField('survey.response')
applicant = models.ManyToManyField(MyUser, related_name="applicant")
created_at = models.DateTimeField(auto_now_add=True)
def get_absolute_url(self):
return reverse('website:ProjectDetails', kwargs={'pk1': self.pk})
Register a user :
def registerManager(request):
#import pdb; pdb.set_trace()
registered = False
if request.method == "POST":
Manager_form = ManagerForm(data=request.POST)
if Manager_form.is_valid():
user = Manager_form.save()
user.set_password(user.password)
user.is_manager = True
user.save()
registered = True
login(request, user)
demoProject = Project.objects.get(name="Project SoftScores")
request.user.project_set.add(demoProject)
return HttpResponseRedirect(reverse('website:hr_index'))
else:
print("Error!")
else:
Manager_form = ManagerForm()
return render(request, 'HR_registration_form.html',
{'Manager_form': Manager_form,
'registered': registered})
Error message:
SystemCheckError: System check identified some issues:
ERRORS:
website.DemoProject.applicant: (fields.E304) Reverse accessor for 'DemoProject.applicant' clashes with reverse ac
cessor for 'Project.applicant'.
HINT: Add or change a related_name argument to the definition for 'DemoProject.applicant' or 'Project.app
licant'.
website.DemoProject.applicant: (fields.E305) Reverse query name for 'DemoProject.applicant' clashes with reverse
query name for 'Project.applicant'.
HINT: Add or change a related_name argument to the definition for 'DemoProject.applicant' or 'Project.app
licant'.
website.Project.applicant: (fields.E304) Reverse accessor for 'Project.applicant' clashes with reverse accessor f
or 'DemoProject.applicant'.
HINT: Add or change a related_name argument to the definition for 'Project.applicant' or 'DemoProject.app
licant'.
website.Project.applicant: (fields.E305) Reverse query name for 'Project.applicant' clashes with reverse query na
me for 'DemoProject.applicant'.
HINT: Add or change a related_name argument to the definition for 'Project.applicant' or 'DemoProject.app
licant'.
WARNINGS:
website.DemoProject.project_hr_admin: (fields.W340) null has no effect on ManyToManyField.
Edited Code:
class BaseProject(models.Model):
name = models.CharField(max_length=250)
team_id = models.ForeignKey(Team, blank=True, null=True)
project_hr_admin = models.ForeignKey('registration.MyUser', blank=True, null=True)
candidat_answers = models.ManyToManyField('survey.response')
applicant = models.ManyToManyField(MyUser, related_name="applicant")
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
def get_absolute_url(self):
return reverse('website:ProjectDetails', kwargs={'pk1': self.pk})
def __str__(self):
return self.name
class Project(BaseProject):
def has_member_responses(self, result=None):
try:
x = Project.objects.get(id=self.id).team_id.members.all()
for i in x:
result = 1
if i.response_set.exists():
result = result * True
else:
result = result * False
return result
except AttributeError:
return False
class DemoProject(BaseProject):
project_hr_admin = models.ManyToManyField('registration.MyUser', blank=True, null=True)
There are several ways you can handle this, but the cleanest In my opinion is to create an abstract BaseProject model and make that the parent class of the Project model and a DemoProject model.
class BaseProject(models.Model):
name = models.CharField(max_length=250)
team_id = models.ForeignKey(Team, blank=True, null=True)
project_hr_admin = models.ForeignKey('registration.MyUser', blank=True, null=True)
candidat_answers = models.ManyToManyField('survey.response')
applicant = models.ManyToManyField(MyUser, related_name="applicant")
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
def get_absolute_url(self):
return reverse('website:ProjectDetails', kwargs={'pk1': self.pk})
Now create the DemoProject as a child of BaseProject
class DemoProject(BaseProject):
project_hr_admin = models.ManyToManyField('registration.MyUser', blank=True, null=True)
Then you can update your registration code to use the new model.
def registerManager(request):
registered = False
if request.method == "POST":
Manager_form = ManagerForm(data=request.POST)
if Manager_form.is_valid():
user = Manager_form.save()
user.set_password(user.password)
user.is_manager = True
user.save()
registered = True
login(request, user)
demo_project = DemoProject.objects.get(name="Demo Project")
request.user.project_set.add(demoProject)
return HttpResponseRedirect(reverse('website:hr_index'))
else:
print("Error!")
else:
Manager_form = ManagerForm()
return render(request, 'HR_registration_form.html',
{'Manager_form': Manager_form,
'registered': registered})
This way, you've seperated the two entities and managed to preserve the behaviour/identitiy of the DemoProject (A DemoProject is still a Project).
This also means you can modify the main Project model without affecting the DemoProject model.
Your main Project model should look like this now
class Project(BaseProject):
# any custom stuff that's unique to a project
pass

Django: Adding more fields to each ManyToMany Field option

Is It possible to add one or more Char Fields to each ManyToMany field option?
My Models:
class engineeringUni(models.Model):
field2 = models.CharField(max_length=200)
des_eng = models.CharField(max_length=1000, default='Add description')
def __str__(self):
return self.field2
def description_eng_universities(self):
return self.des_eng
class engineering_courses(models.Model):
course_name = models.CharField(max_length=400)
course_description = models.CharField(max_length=1000, default='This is a description')
course_offered_by = models.ManyToManyField(engineeringUni, related_name='course_offered_by')
course_duration = models.IntegerField(blank=False, default='2')
def __str__(self):
return self.course_name
def description_course(self):
return self.course_description
def offered_by_courses(self):
return self.course_offered_by
def duration_courses(self):
return str(self.course_duration)
As you can see in the image, I have the options in the ManyToMany field. Those options are:
University 1
University 2
University 3
What I want to have is an additional text (Char) field next to each of these options (University 1, University 2, University 3).
Is this possible?
EDIT 1:
Current code:
class engineering_courses(models.Model):
course_name = models.CharField(max_length=400)
course_description = models.CharField(max_length=1000, default='This is a description')
course_offered_by = models.ManyToManyField(
engineeringUni,
through='ThroughModel',
through_fields=('course', 'university'),
)
course_duration = models.IntegerField(blank=False, default='2')
def __str__(self):
return self.course_name
def description_course(self):
return self.course_description
def offered_by_courses(self):
return self.course_offered_by
def duration_courses(self):
return str(self.course_duration)
class ThroughModel(models.Model):
course = models.ForeignKey(engineering_courses, on_delete=models.CASCADE)
university = models.ForeignKey(engineeringUni, on_delete=models.CASCADE)
additional_text = models.CharField(max_length=200)
EDIT 2: Problem fixed. I was getting that no table error because I had deleted the migration files and on deleting database (db.sqlite3) file and applying migration again, It fixed.
You can use a through model in the ManyToManyField (docs). This model can be used to store any additional fields.
class engineering_courses(models.Model):
# ...
course_offered_by = models.ManyToManyField(engineeringUni, related_name='course_offered_by', through='ThroughModel')
class ThroughModel(models.Model):
course = models.ForeignKey(engineering_courses)
university = models.ForeignKey(engineeringUni)
additional_text = models.CharField()
Take another look at the django docs referenced in the answer from arjun27. You have more than one foreign key in your ThroughModel, so django is confused. Try specifying the through fields in your engineering_course model, migrate the changes, and see if that works.
Mark

Django model foreignkey queries

So i have this two models in django:
class Course(models.Model):
def get_image_path(self, filename):
return os.path.join('courses', str(self.slug), filename)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Course, self).save(*args, **kwargs)
name = models.CharField(max_length=255, verbose_name="Nombre")
description = models.CharField(max_length=255, verbose_name="DescripciĆ³n")
price = models.DecimalField(max_digits=12,decimal_places=2, verbose_name="Precio")
slug = models.SlugField(blank=True, max_length=255)
icon_img = models.ImageField(upload_to=get_image_path, blank=True, null=True, verbose_name="Imagen")
background_color = ColorField(default="#026085")
class Meta:
verbose_name = "curso"
verbose_name_plural = "cursos"
class UserCourse(models.Model):
user = models.ForeignKey(User)
course = models.ForeignKey(Course)
So whenever a user "buys" a course, it is stored in UserCourse. I have a view where the system shows a list of all the courses the user has bought. This is the view code:
def user_course_list_view(request, username):
context_dict = {}
try:
user_courses = UserCourse.objects.filter(user=request.user).course_set
context_dict['courses'] = user_courses
context_dict['heading'] = "Mis cursos"
except:
context_dict['courses'] = None
context_dict['heading'] = "Mis cursos wey"
return render(request, 'courses/course_list.html', context=context_dict)
I dont know where is the error and I cant seem to catch the exception (im using django with docker)
tl;dr
Something like this should work.
usercourse_objects = UserCourse.objects.filter(user=request.user).select_related('course')
user_courses = [x.course for x in usercourse_objects]
Explanation
There are multiple ways to do this, but one way would be to first get all the UserCourse objects for the current user:
usercourse_objects = UserCourse.objects.filter(user=request.user)
Then, for each UserCourse object, get the related Course:
user_courses = [x.course for x in usercourse_objects]
Now, the second line causes N database queries (one for each time we follow the course foreign key relation. To prevent this, the first line can be changed to:
usercourse_objects = UserCourse.objects.filter(user=request.user).select_related('course')
This pre-populates the course attribute of the UserCourse objects. More info about select_related() can be found here.

Take last object in queryset and set value in field

I have app in Django 1.8 and I want to take last object (based on pub_date) and set for this object filed is_mainteaser on True and rest ssould be set on False.
Here is my code, but latest object hasn't field set to True.
class ArticleListView(ListView):
model = Article
queryset = Article.objects.order_by('-pub_date')
def get_context_data(self, **kwargs):
context = super(ArticleListView, self).get_context_data(**kwargs)
lates_object = Article.objects.latest('pub_date')
lates_object.is_mainteaser = True
return context
Here is my model:
class Article(model.Models):
title = models.CharField(max_length=255)
short_text = models.TextField(max_length=10000, default='')
image = FilerImageField(null=True)
pub_date = models.DateTimeField('date published')
online_from = models.DateTimeField('online from', blank=True)
online_to = models.DateTimeField('online to', blank=True)
position = models.PositiveIntegerField(default=0)
is_mainteaser = models.BooleanField(default=False)
def __str__(self):
return self.title
class Meta:
ordering = ['position']
When you have object instance and change model attribute you must save instance. Example:
lates_object = Article.objects.latest('pub_date')
lates_object.is_mainteaser = True
lates_object.save()
I think better for this solution is use django signals or action when you add new article. In ListView is't good solution to do it that.

Categories

Resources