Add an exception for model relationship of a specific object - python

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

Related

Django display ForeignKey field in Admin

I'm working on a project using Python(3.7) and Django(3) in which I have implemented a few models. One of them is ReportsModel which has ForeignKey field to other models. Now I want to display other model data in ReportsModel admin.
Here what I have tried so far:
From models.py:
class ReportsModel(models.Model):
cdr_report = models.ForeignKey(CurrencyDistributionModel,
on_delete=models.CASCADE, null=True, default=None)
cme_report = models.ForeignKey(CurrencyManagementExpenditureModel,
on_delete=models.CASCADE, null=True, default=None)
cps_report = models.ForeignKey(CurrencyProcessingStorageModel,
on_delete=models.CASCADE, null=True, default=None)
cma_report = models.ForeignKey(CurrencyManagementAssetsModel,
on_delete=models.CASCADE, null=True, default=None)
def __str__(self):
if self.cdr_report is not None:
return self.cdr_report.RequestId
elif self.cme_report is not None:
return self.cme_report.RequestId
elif self.cps_report is not None:
return self.cps_report.RequestId
elif self.cma_report is not None:
return self.cma_report.RequestId
To display the ForeignKey field in admin I'm using the django_reverse_admin package, here how I did that:
From admin.py:
class ReportAdmin(ReverseModelAdmin):
report = None
if ReportsModel.cdr_report is not None:
report = 'cdr_report'
elif ReportsModel.cme_report is not None:
report = 'cme_report'
elif ReportsModel.cps_report is not None:
report = 'cps_report'
elif ReportsModel.cma_report is not None:
report = 'cma_report'
search_fields = ['name']
inline_reverse = [report]
inline_type = 'stacked'
admin.site.register(ReportsModel, ReportAdmin)
now in the admin, it only works for the cdr_report, when I add a report of type cme_report, I'm getting the RequestField correctly, but the cme_report field is empty.
How can I display the Inline Admin on the base of condition?
class ReportAdmin(admin.ModelAdmin):
list_display = ("id", "someVariable" )
def someVariable(self, obj):
# do your logic, query or just return FK model data
return obj.CurrencyDistributionModel.<WhateverIsYourField>
admin.site.register(ReportsModel, ReportAdmin):

UserCheckout matching query does not exist

I'm trying to display all orders matching each logged in user, I dont understand why it gives me issues when trying to filter for users as it gives me that UserCheckout does not have any matching queries:
orders/views.py
class OrderList(LoginRequiredMixin, ListView):
queryset = Order.objects.all()
def get_queryset(self):
user_check_id = self.request.user.id
user_checkout = UserCheckout.objects.get(id=user_check_id)
return super(OrderList, self).get_queryset().filter(user=user_checkout)
orders/mixins.py
class LoginRequiredMixin(object):
#method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(request,*args, **kwargs)
orders/models.py
class UserCheckout(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete = models.CASCADE) # not required as to allow guests to checkout too
email = models.EmailField(unique=True) # required, unique as if there the guest already has an authentication just one email needed
def __str__(self):
return self.email
class Order(models.Model):
status = models.CharField(max_length=120, choices=ORDER_STATUS_CHOICES, default='created')
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
user = models.ForeignKey(UserCheckout, null=True, on_delete=models.CASCADE)
billing_address = models.ForeignKey(UserAddress, related_name='billing_address', null=True,on_delete=models.CASCADE)
shipping_address = models.ForeignKey(UserAddress, related_name='shipping_address', null=True, on_delete=models.CASCADE)
shipping_total_price = models.DecimalField(max_digits=50, decimal_places=2, default=5.99)
order_total = models.DecimalField(max_digits=50, decimal_places=2)
def __str__(self):
return str(self.cart.id)
Error it gives me:
DoesNotExist at /orders/
UserCheckout matching query does not exist.
You are getting an error because you are trying to use the User's primary key (id) as the UserCheckout's primary key i.e. the lines:
user_check_id = self.request.user.id
user_checkout = UserCheckout.objects.get(id=user_check_id)
Change these lines to:
user = self.request.user
user_checkout = UserCheckout.objects.get(user=user)
Also this can throw an Exception if a UserCheckout instance doesn't exist you can catch that using try-except or use django's shortcut function get_object_or_404:
from django.shortcuts import get_object_or_404
user_checkout = get_object_or_404(UserCheckout, user=user)

if-else statement in python django

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)

Writing a view to allow user to add related data for a customer, like comments for example; on a single page

I have working models, forms, views and urls for a django CRUD app managing customer functions for a business. I just cant seem to figure out how to write a view to allow a user to add comments, or other data related to the customer and stored in other models using a single view and template.
So for example; for customer a, all the comments for customer a with the option to add, amend etc.. and the same for the other related models.
I understand how to do it for one I will be able to make quick progress. (old school programmer here)
Here is what I am working with - keeping it simple.
MODELS
class Emergency(models.Model):
# Fields
name = CharField(null = False, blank = False, max_length=60)
address = TextField(blank=True, null=True, help_text='Street and town', verbose_name='Address')
telephone = CharField(blank=False, null=False, unique= True, max_length=20)
relationship = CharField(choices=(('P', 'Parent'),('S', 'Son'),('D', 'Daughter'),('R', 'Relative'),('L', 'Partner')),max_length = 1,default='R')
class Meta:
ordering = ('-pk',)
def __unicode__(self):
return u'%s' % self.pk
def get_absolute_url(self):
return reverse('conform_emergency_detail', args=(self.pk,))
def get_update_url(self):
return reverse('conform_emergency_update', args=(self.pk,))
class Client(models.Model):
# Fields
surname = CharField(null = False, blank = False, max_length=30)
name = CharField(null = False, blank = False, max_length=60)
# Relationship Fields
emergencycontact = models.ForeignKey(Emergency, on_delete=models.CASCADE, name = 'Emergency Contact')
class Meta:
ordering = ('-pk',)
def __unicode__(self):
return u'%s' % self.pk
def get_absolute_url(self):
return reverse('conform_client_detail', args=(self.pk,))
def get_update_url(self):
return reverse('conform_client_update', args=(self.pk,))
class Clientnotes(models.Model):
# Fields
slug = AutoSlugField(populate_from='name', blank=True)
created = DateTimeField(auto_now_add=True, editable=False)
last_updated = DateTimeField(auto_now=True, editable=False)
note = CharField(blank=False, null=False, max_length= 300 )
# Relationship Fields
modified_by = models.ForeignKey(User, related_name='clientnotes_modified_by', on_delete=models.CASCADE, name= 'Changed by')
clientnotes = models.ManyToManyField(Client, name = 'Clients notes')
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.slug
def get_absolute_url(self):
return reverse('conform_clientnotes_detail', args=(self.slug,))
def get_update_url(self):
return reverse('conform_clientnotes_update', args=(self.slug,))
FORMS
class ClientForm(forms.ModelForm):
class Meta:
model = Client
fields = ['surname', 'name']
class ClientnotesForm(forms.ModelForm):
class Meta:
model = Clientnotes
readonly_fields = ['slug', 'modified_by']
fields = ['note']
VIEWS
class ClientListView(ListView):
model = Client
class ClientCreateView(CreateView):
model = Client
form_class = ClientForm
class ClientDetailView(DetailView):
model = Client
class ClientUpdateView(UpdateView):
model = Client
form_class = ClientForm
TEMPLATE NAMES
client_detail.html
client_form.html
client_list.html
I have simple views, forms and templates to list, view detail and add and it all works well - with the exception of related models because i am not able to add both models at the same time. I need a simple clear simpletons guide with what i have provided so it clicks into place.

Related Field got invalid lookup: icontains

I am trying to include a search field inside my home page. It works for some of the module field. My problem is when I use a ForeignKey field (correct me please if I am wrong).
models.py
class Location(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
my_location = models.CharField(max_length=120, choices=LOCATION_CHOICES)
update_date = models.DateField(auto_now=True, null=True)
def __str__(self):
return self.my_location
class UserProfile(models.Model):
user = models.ForeignKey(User)
# The additional attributes we wish to include.
user_base = models.CharField(max_length=120, choices=LOCATION_CHOICES)
user_position = models.CharField(max_length=120)
user_phone = models.PositiveIntegerField()
def __unicode__(self):
return self.user.username
views.py
def search_by_location(request):
if 'q' in request.GET and request.GET['q']:
q = request.GET['q']
locations = Location.objects.filter(my_location__icontains=q).order_by('-update_date')
else:
locations = Location.objects.order_by('-update_date')
context = {'locations': locations}
return render(request, 'index.html', context)
My problem is if I use user inside the filter query instead of my_location I receive the error:
Related Field got invalid lookup: icontains
Please any advice on how to troubleshoot or any documentation I can read.
You can use icontains lookup on text fields. user is related (integer) field. Instead of user use user__username.
locations = Location.objects.filter(user__username__icontains=q)
class SearchView(ListView):
model = Profile
template_name = 'blog/search_results.html'
context_object_name = 'all_search_results'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user_name = self.request.GET.get('search', '')
context['all_search_results'] = Profile.objects.filter(user__username__icontains=user_name )
return context
here is another example on how to filter objects. if searching for a user, remember to user user_username__icontains=user_name
also remember that if you use Profile your'll get a different id than if you use User

Categories

Resources