Connect and present data from two different tables in django - python

I'm trying to easily present data from two different tables (classes). I have an Environment class with all the environments details and a Changes class which contain history changes on all my environments.
My view is currently showing all my Environment details. I want to add to this view the last change been made on each environment (e.g last modified by: User).
My models.py look like this:
class System(models.Model):
system_name = models.CharField(max_length=40, blank=True)
system_id = models.CharField(max_length=100, blank=True)
system_clusters = models.ManyToManyField(Cluster, blank=True)
system_owner = models.CharField(max_length=20, blank=True)
def __str__(self):
return self.system_name
class Changes(models.Model):
date = models.DateTimeField(auto_now_add=True)
cluster = models.ForeignKey(System, on_delete=models.CASCADE)
user = models.CharField(max_length=20, blank=True)
change_reason = models.CharField(max_length=50, blank=True)
def __str__(self):
return self.date
At first, i though to pass a dictionary to my template with the system as a key and a change as a value:
last_changes = {}
change = Changes.objects.filter(cluster__in=s.system_clusters.all()).order_by('-id')[0]
last_changes[s.system_id] = change.change_reason
Even though it partially works (I still trying to parse the dict in my template), I feel like this is not the right approach for the task.
I'm hoping to reach a result where I can just call system.last_change in my template. Can I add another field for System class that will point to his last_change in the Changes table?

You can write a method on System to return the last change for an item:
def last_change(self):
return self.changes_set.order_by('-date').first()
Now you can indeed call system.last_change in the template.

Related

How to transfer data from one list to another in Django?

I'm doing a small to-to list, I'm stuck in views.py, there are to-do
tasks, in-progress tasks and done tasks, I want to move a task from the
to-do task list to the in-progress task list, I can't figure out how to
delete the data in the to-to task and make new data same as to-do task
in the in-progress task at the same time. It would be great if anyone
can help, I'm totally new to Django. Thanks.
'''
models.py
class Todo(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
name = models.CharField(max_length=20)
start_date = models.DateTimeField(default=datetime.datetime.now)
due_date = models.DateTimeField(default=datetime.datetime.now)
def __str__(self):
return self.text[:60] + "..."
class Progress(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
name = models.ForeignKey(Todo, on_delete=models.CASCADE)
start_date = models.DateTimeField(default=datetime.datetime.now)
due_date = models.DateTimeField(default=datetime.datetime.now)
def __str__(self):
return self.text
'''
I would suggest only having one class, with an extra row for whether they are in progress or not. This will save you from creating and deleting django and DB objects over and over, when through their lifecycle they are the same information. You can achieve this in a few ways: a float field to track percentage of completeness, or just a boolean. For simplicity of example, I'll use a boolean.
`class Todo(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
name = models.CharField(max_length=20)
start_date = models.DateTimeField(default=datetime.datetime.now)
due_date = models.DateTimeField(default=datetime.datetime.now)
in_progress = models.BooleanField(default=False)
def __str__(self):
return self.name`
Then in your views you can query for those tasks that are or are not in progress. As mentioned above you could also use a float field and then do a search for anything greater that 0.

Changing default value of cell using DJango and SQlite3

I have a problem, I am doing project in Django for my University, and I don't know how can I change value of cell in Database using views.py. My application is an application to do exams online and problem is that many users need to use it at the same time, so I need to do relations in database, like every question has an answer and that answer is provided by one user. And there is problem, I don't know how can I change this dynamically in Views.py.
This is my code from Views.py:
if form.is_valid():
if username == Users.objects.latest('name'):
Choice.objects.username = Users.objects.get('name')
And my models.py:
class Answers(models.Model):
question = models.ForeignKey(Questions, on_delete=models.CASCADE)
text = models.TextField()
def __str__(self):
return self.text
class Users(models.Model):
name = models.CharField(max_length=30)
pass = models.CharField(max_length=30)
def __str__(self):
return self.name
class Choice(models.Model):
username = models.ForeignKey(Users, null=True, on_delete=models.CASCADE)
question = models.ForeignKey(Questions, null=True, on_delete=models.CASCADE)
answer = models.CharField(null=True,max_length=50)
class Questions(models.Model):
text = models.CharField(max_length=150)
madeBy = models.ForeignKey(User, null=True, blank=False, default='kacper', on_delete=models.CASCADE)
def __str__(self):
return self.text
Also if you have any other idea how could I improve this would be great, it's first time that I'm doing something in DJango.
If I understand your question correctly you want to update("how can I change value of cell ...") an specific object. To do this you can use following command :
YourModel.objects.filter(pk=yourobject_pk).update(username=Users.objects.get('name'))
Have this in mind, first you have to filter the object you want to update(I suggest doing this by id) and then update the field(cell) you want.

unique_together with a field from a foreign key in a through table for a ManyToMany relation

I am developing a Django 2.0 project app. It has a (non-working) models.py file, which looks something like this:
from django.db import models
from django.utils import timezone
class Computer(models.Model):
name = models.CharField(max_length=25)
def __str__(self):
return "Computer {}".format(self.name)
class Software(models.Model):
name = models.CharField(max_length=25)
description = models.CharField(max_length=1024, blank=True)
def __str__(self):
return self.name
class SoftwareVersion(models.Model):
software = models.ForeignKey(Software, on_delete=models.CASCADE, related_name="versions")
version = models.CharField(max_length=100)
released_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return "{} {}".format(self.software, self.version)
class ComputerSoftwareBundle(models.Model):
computer = models.ForeignKey(Computer, on_delete=models.CASCADE, related_name="bundles")
installed_at = models.DateTimeField(default=timezone.now)
versions = models.ManyToManyField(SoftwareVersion, through="BundleSoftwareVersion", related_name="bundles")
class BundleSoftwareVersion(models.Model):
bundle = models.ForeignKey(ComputerSoftwareBundle, on_delete=models.CASCADE)
version = models.ForeignKey(SoftwareVersion, on_delete=models.CASCADE)
class Meta:
unique_together = (("bundle", "version__software"),)
The app tracks software bundles currently or previously installed on computers. The thing here is that a bundle should not contain more than one version of the same software. Also, SoftwareVersion should contain a reference to Software, because the same version string has a different meaning for different pieces of software.
The code does not work as described in this Stackoverflow answer. I left the unique_together line in to illustrate what I am trying to achieve.
I've tried to work around this limitation of Django (not being able to use fields referred to via a foreign key in unique_together) by overriding the save and validate_unique methods in BundleSoftwareVersion but that did not work out completely well. Here's the implementation I have tried:
class BundleSoftwareVersion(models.Model):
bundle = models.ForeignKey(ComputerSoftwareBundle, on_delete=models.CASCADE)
version = models.ForeignKey(SoftwareVersion, on_delete=models.CASCADE)
def save(self, *args, **kwargs):
self.validate_unique()
super().save(*args, **kwargs)
def validate_unique(self, exclude=None):
super().validate_unique(exclude)
bundle_versions = BundleSoftwareVersion.objects.filter(bundle=self.bundle,
version__software=self.version.software)
count = len(bundle_versions)
if not self.pk:
# if this instance is not stored in the database,
# we need to increment the count to take this instance
# into account
count += 1
if count > 1:
raise ValidationError("There already is an instance of software '{}' in this bundle.".format(self.version.software))
I have thus far tried out these models via the admin site. The checks work when changing an existing ComputerSoftwareBundle (the admin site displays a message next to the offending entry), but adding results in an uncaught exception.
Is there a better way to enforce this kind of uniqueness?
I have come up with a workaround:
class BundleSoftwareVersion(models.Model):
bundle = models.ForeignKey(ComputerSoftwareBundle, on_delete=models.CASCADE)
version = models.ForeignKey(SoftwareVersion, on_delete=models.CASCADE)
_software = models.ForeignKey(Software, on_delete=models.CASCADE, null=True, editable=False)
class Meta:
unique_together = (("bundle", "_software"),)
def save(self, *args, **kwargs):
self._software = self.version.software
super().save(*args, **kwargs)
As you can see, I now have a helper field _software which is used in unique_together and into which the self.version.software is stored on each save.
So far, I have experienced one downside with this approach: trying to save a ComputerSoftwareBundle containing duplicate software instances results in an error page for IntegrityError being displayed instead of an error message within the form.
I would appreciate suggestions on how to fix this downside, or even suggestions for a different approach altogether.

Referencing Variables in Another Django Model with Foreign Key

I have a Project Model where a user can add a Project with an associated Position(s) for the Project. As an example, Website would be project whereas web developer would be the Position. Here are two models.
class Project(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='project')
created_at = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=255)
description = models.TextField()
complete = models.BooleanField(default=False)
def __str__(self):
return self.title.title()
class Position(models.Model):
project = models.ForeignKey(Project, default='',related_name='positions')
name = models.CharField(max_length=140)
description = models.TextField()
skill = models.ForeignKey(Skill, default='')
filled = models.BooleanField(default=False)
def __str__(self):
return '{} - {}'.format(self.project.title.title(), self.name.title())
I have a view created to show the user's profile and any current or past projects worked on. See below:
class ProfileView(LoginRequiredMixin,generic.TemplateView):
template_name = 'accounts/profile.html'
login_url = settings.LOGIN_REDIRECT_URL
def get_context_data(self, **kwargs):
context = super(ProfileView, self).get_context_data(**kwargs)
lookup = kwargs.get('username')
user = models.User.objects.get(username=lookup)
profile = models.UserProfile.objects.prefetch_related('skills').get(user=user)
context['profile'] = profile
context['skills'] = [skill for skill in profile.skills.all()]
projects = models.Project.objects.all()
context['current_projects'] = projects.filter(Q(owner=user) & Q(complete=False))
context['past_projects'] = projects.filter(Q(owner=user) & Q(complete=True))
return context
I'm having trouble figuring out how to reference the position(s) for a particular projects in my html template. I know that if i try in python shell, i can query the position class and get all objects and then grab the project variables from there.
I tried to create a position 'context' in the view like this:
positions = m.Position.objects.all()
context['positions'] = positions.filter(Q(owner=user)& Q(complete=False))
But Django doesn't like that 'owner' variable--which i understand since i'm just grabbing data from positions. I know in the shell i can do something like m=Position.objects.all() and then do a m[0].project.title to get the project data. For some reason i just can't understand how to put it all together in the code. Any help is greatly appreciated! Been racking my brain on this one for a while!
To traverse related objects, you can use the lowercased name of the model followed by __ (2 underscores) and the field name in the other model.
So instead of this:
positions.filter(Q(owner=user)& Q(complete=False))
Write like this:
positions.filter(Q(project__owner=user) & Q(project__complete=False))

Django: Can't query a foreign field

I'm still a novice so any help is gladly appreciated. Running Django 1.10
I'm trying to retrieve all the profiles that are assigned a particular manager but my query set always comes up empty.
Model.py
Blockquote
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=30, blank=False)
last_name = models.CharField(max_length=30, blank=False)
email = models.EmailField( blank=True, help_text='Optional',)
receive_email_notifications = models.BooleanField(default=False)
manager = models.ForeignKey(User, unique=False, blank=True, related_name='+', null=True)
def get_full_name(self):
"""
Returns the first_name plus the last_name, with a space in between.
"""
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def publish(self):
return self.save
def __str__(self):
return str(self.user)
View.py
Blockquote
def instrument_list(request):
# pulls all instruments from instrument model
instruments = Instrument.objects.all().order_by('instrument_name')
test = Profile.objects.filter(manager='jenn')
print(test)
# pulls all checklists from checklist model
checklists = Checklist.objects.all().order_by('created_date')
# takes instruments, pushes them to template with variable 'instruments'
return render(request, 'blog/instrument_list.html', {'instruments': instruments, 'checklists': checklists})
I've also tried filtering a single profile entry (with a non-foreign key attribute) and printing how managers are saved in the database and the output looked like this
Blockquote
<User: jenn>
However, even when I try filtering with that output, my query sets come up empty
Blockquote
test = Profile.objects.filter(manager='<User: jenn>')
I think I need to adjust my filter parameter to something the database can match against but I'm not sure what that format is. I've tried looking through the documentation but haven't found exactly what I'm looking for.
But that's just a string representation of a model instance. You need the actual instance.
jenn = User.objects.get(username="Jenn")
test = Profile.objects.filter(manager=jenn)
Of course, once you already have jenn as an instance, to can use the reverse accessor of the fk instead:
test = jenn.profile_set.all()
And if you don't have jenn, and you don't need it, you can do the whole thing in one query:
test = Profile.objects.filter(manager__username="Jenn")
I've also tried filtering a single profile entry (with a non-foreign key attribute) and printing how managers are saved in the database and the output looked like this
That's not how managers are saved in databases, thats just a "readable" representation of an instance user.
If you want to filter on a manager you can do something like that :
test = Profile.objects.filter(manager__pk= primary_key_of_manager)
or
temp_manager = User.objects.get(...)
test = Profile.objects.filter(manager=temp_manager)

Categories