Append to queryset object in Django - django

My Django Model:
class Job(models.Model):
title = models.CharField(_('Job Title'),max_length=150, blank=True, default="")
description = models.CharField(_('Description'), max_length=250, blank=True, default="")
user = models.ForeignKey('User', verbose_name="User", on_delete=models.CASCADE, null=True)
def __str__(self):
return self.title
I have a queryset of django objects:
>>> jobs = Job.objects.all()
<QuerySet [<Job: university>, <Job: companies>, <Job: inside>, <Job: outside>]>
I want to iterate over them, and update their dict (merge their dict with a new dict) with a key that they don't have. Is it possible to do something like this?
for job in jobs:
job.update('new_key' : 'new_value') #This returns error
To obtain the job object with the following keys: title, description, user, new_value.
Why do I want to do this? To be easier to iterate over those values that are correlated with jobs with only one for loop in the templates.
I don't want to use Job.objects.all().values() because that way I can't do job.user.name in the templates and get user name or user information.

Related

django orm foreign key latest data using filter query

class Schedule(models.Model):
user = models.ForeignKey(USER, on_delete=models.SET_NULL, null=True)
area = models.ForeignKey(Site, on_delete=models.SET_NULL, null=True)
created_at = models.DateTimeField(auto_now_add=True, null=True)
updated_at = models.DateTimeField(auto_now=True, null=True)
area = Schedule.objects.values("area").annotate(latest=Max('created_at')).values("area")
latest = Schedule.objects.values("area").annotate(latest=Max('created_at')).values("latest")
Schedule.objects.filter(created_at__in=latest, area__in=area)
I got the value I want.
However, I am uneasy when I filter with ForeignKey and DateTimeField. Can't there be a better way?
Also, can't you make it cleaner other than the code above?
Guess you can create a Manager for your Model and use selected_related feature, it will create quick query for you, and it`s ready "out-of-the-box" Django solution. Plz see Django docs.
Here`s example based on your code
In Model.py something like
class SheduleManager(model.Manager):
def all_prefetched_data(self):
qs = self.get_queryset()
qs = qs.select_related(
'area_set'
)
return qs
in the same Model.py you need to assign your manager in Shedule model
listing = SheduleManager
Now in view you can sort db items by creation date, query with the ForiegnKey fetching through all your db. You also can display result, for example in your_template.html with the dictionary b_list
view.py
def GetList(request):
sh_list = Schedul.listing.all().order_by('-created_at')
return render(request, 'your_template.html', {'b_list': sh_list})

Django Nested Form - Always Showing Object instead of model details

I'm working on a Django project generated via Mezzanine. I've been able to create my models, however I want to have a form where an admin can select from a list to assign a value in a many to many or a one to many relationship. For example, I have a model for Schemas:
class Schema(AutoCreatedUpdatedMixin, SoftDeleteMixin):
"""List of all Schemas in a given database"""
name = models.CharField(max_length=128, null=False)
status = models.BooleanField(max_length=128, null=False, default=True, verbose_name="Is Active")
description = models.CharField(max_length=65535, null=True, blank=True, default=None)
database = models.ForeignKey(Database, on_delete=models.CASCADE)
pull_requests = models.ManyToManyField(Link)
questions = models.ManyToManyField(Question, blank=True)
comments = models.ManyToManyField(Comment, blank=True)
technical_owners = models.ManyToManyField(Employee, related_name='technical_owners_schemas', blank=True)
business_owners = models.ManyToManyField(Employee, related_name='business_owners_schemas', blank=True)
watchers = models.ManyToManyField(Employee, related_name='watchers_schemas', blank=True)
def __unicode__(self):
return "{}".format(self.name)
And I have a model for Employees
class Employee(AutoCreatedUpdatedMixin, SoftDeleteMixin):
"""List of people with any involvement in tables or fields: business or technical owners, developers, etc"""
name = models.CharField(max_length=256, blank=False, null=False, default=None, unique=True)
email = models.EmailField(blank=True, null=True, unique=True)
def __unicode__(self):
return "{}".format(self.employee)
An employee can own multiple schemas and a schema can be owned by multiple employees. My database has an active employee in it, however when I try to create a Schema the employee shows up as Employee Object. Rather I would want the form to show the Employee.name. How can I do this? My admin file contains the following:
class SchemasAdmin(admin.ModelAdmin):
list_display = ['name', 'status', 'database', 'description']
ordering = ['status', 'database', 'name']
actions = []
exclude = ('created_at', 'updated_at', 'deleted_at')
First of all are you using python 2 or 3? For 3, the __str__ method should be used instead of __unicode__. I am writing this because it seems that there's a problem with the __unicode__ method of Employee, which although is defined as:
def __unicode__(self):
return "{}".format(self.employee)
th Employee class does not have an employee attribute (unless there's such an attribute in the mixins that class inherits from (AutoCreatedUpdatedMixin, SoftDeleteMixin) but I don't think that is the case.
In any case, the problem is that you haven't defined a propery __str__ (if using python 3) or __unicode__ (for python 2) method on the Employee class - just define it like:
return self.name
and you should see the employee's name in the django admin select fields.

order_by causing not distinct items

I've implemented a messaging system:
class Message(models.Model):
user = models.ForeignKey(User, unique=False, related_name = 'messages')
conversation = models.ForeignKey('Conversation', related_name = 'messages')
body = models.TextField(max_length=750)
reads = models.ManyToManyField(User, related_name='read_messages', null=True, blank=True)
# Other
date_created = models.DateTimeField(auto_now=False, auto_now_add=True, blank=True)
date_modified = models.DateTimeField(auto_now=True, auto_now_add=False, blank=True)
class Conversation(models.Model):
participants = models.ManyToManyField(User, related_name='conversations')
type = models.CharField(max_length=1, default="D", choices=config.CONVERSATION_TYPE_OPTIONS)
Using Django Rest Framework, I'd like to order a conversation by the last message.
class ConversationFilter(filters.BaseFilterBackend):
"""
Filters to only show by current user
"""
def filter_queryset(self, request, queryset, view):
return queryset.filter(
participants=request.user,
).order_by('-messages__date_created')
However once I add the order_by method, the queries are no longer distinct. Adding distinct() does not work either. What is going on here?
You have a one to many relationship between Conversation and Message.
When you join the message table into the Conversation query (which happens when you add the order_by clause using messages), then you will get multiple Conversation entries, one for each message.

How to construct a Django query that filters each element of a list?

I am trying to construct a query which takes the currently logged in users nearestzips which is a list of 5 postal codes, and then filters through all items for sale that match these 5 postal codes.
models.py
class MyProfile(UserenaBaseProfile):
user = models.OneToOneField(User,
unique=True,
verbose_name=_('user'),
related_name='my_profile')
streetaddress=models.CharField(null=True, blank=True, max_length=30)
city = models.CharField(null=True, blank=True, max_length=20)
state = models.CharField(null=True, blank=True, max_length=20)
zipcode = models.IntegerField(_('zipcode'),
max_length=5, null=True, blank=True)
nearestzips = models.Charfield(null=True, blank=True, max_length=80)
views.py
class Entry(models.Model):
headline= models.CharField(max_length=200,)
body_text = models.TextField()
author=models.ForeignKey(settings.AUTH_USER_MODEL, related_name='entryauthors')
pub_date=models.DateTimeField(auto_now_add=True)
zipcode =models.IntegerField(null=True, max_length=10)
printing nearestzips from the console
print testprofile.nearestzips
>>>[<PostalCode=97202>, <PostalCode=97201>, <PostalCode=97215>, <PostalCode=97239>, <PostalCode=97214>]
And finally, here is the query I am trying to construct.
latest_entries = Entry.objects.filter(zipcode="user.nearestzips")
My question is, since nearestzips is a list, how can I filter through the 5 elements of that list? Can I simply add [0:4] after 'nearestzipcodes' or do I have to do something like this:
latest_entries = Entry.objects.filter(zipcode="user.nearestzips[0]").filter(zipcode="user.nearestzips[1]").filter(zipcode="user.nearestzips[3]"), etc.
Any help would be apprecitaed, thanks.
Since nearestzips is a string, you'll need to first parse MyProfile.nearestzips to get a proper list. If you're already doing that somewhere, your query is pretty simple:
zip_list = user.nearestzips # Assuming this returns a proper list
latest_entries = Entry.objects.filter(zipcode__in=zip_list)
If user.nearestzips isn't returning a list, you can add a custom method to the MyProfile object to return the zip codes in list format:
def get_nearestzips(self, *args, **kwargs):
zip_list = self.nearestzips.replace("PostalCode=","")
return zip_list.split(",")
You can use the __in field lookup in django.
https://docs.djangoproject.com/en/1.7/ref/models/querysets/#in
The syntax is filter(col_name__in=list). Since your input is a dictionary you have to use the list.values() function to generate the data for your "in" filter input.
So put all together:
nearby_entry = Entry.objects.filter(zipcode__in=testprofile.nearestzips.values())
Update Feb13:
If you nearestzips is a queryset then you have to either convert it to a list or use values_list to get the data instead.
Method1: convert
zip_list = [z.postalcode for z in testprofile.nearestzips]
Method2: values_list assuming nearestzips is a many2many field
zip_list = testprofile.nearestzips.values_list('postalcode',
flat=True)

Django admin custom queryset for a custom action

I am a bit lost on how to perform a specific queryset in django admin. Below are my models.
class People(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=35)
phone_number = models.CharField(null=True, blank=True, max_length=15)
def __str__(self):
return self.first_name
class Meta:
verbose_name_plural = 'People'
class Group_and_message(models.Model):
name = models.CharField(max_length=30, null=True)
people = models.ManyToManyField(Person)
message_body = models.TextField(max_length=140)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
def __str__(self):
return self.name
In Admin, I have created a custom action.
def send_message(modeladmin, request,queryset):
pass
My question is to be able, when selecting a "group_and_message" object in the admin dashboard via the checkbox, be able to retrieve "id" and "phone_number" of the selected object so i can use it to perform "send_message" custom action.
Below is the equivalent of basic of a few queryset steps that showcase what i am trying to achieve(just for illustration purpose)
g = Group_and_message.objects.last() #self instead of last is what i want;
g1 = g.people.all()
g2 = g1.values_list("id","phone_number");
g3 = dict(g2)
The result gives me the "id" and "phone number".
Any help would be much appreciated.
You need to access the Group_and_message via the backwards relation. In this case for you, it should be group_and_message_set.
def send_message(modeladmin, request,queryset):
phone_map = dict(People.objects.filter(
group_and_message_set__in=queryset,
).distinct().values_list('id', 'phone_number'))
# Do something
class Group_and_messageAdmin(admin.ModelAdmin):
actions = ['send_message']
As an aside, you shouldn't have underscores in your model names. Rather than Group_and_message, it'd be more pythonic/django-like to use GroupMessage.