When I build a model in Django, I add the following information:
def __unicode__(self):
return self.some_field
class Meta:
ordering = ['some_field_to_order_by']
Is it possible to set ordering based on a sort of if/else scenario?
For example, I have a customer model which, for sake of argument, has these fields:
first_name
last_name
company_name
is_company (boolean)
If the customer is a Company, I only add information to the company_name field and set is_company=True, leaving the other two blank. If the customer is a person, then I add information to the first_name and last_name fields, leaving the company_name blank and the is_company=False.
I want to sort these records by last_name if the is_company field is False and company_name if is_company is True.
Is this possible?
EDIT For an example (per request, sort of)
For my app, this customer table holds information regarding owners of security systems. Sometimes, a security system is installed in a residential setting. In this case, the owner of the system is a person -- thus, I would enter the first_name and last_name into the customer record. Sometimes the system is installed in a commercial setting, therefore the owner is a company. For this I enter only the company_name field, leaving the other fields blank.
Now, when I provide an estimate for a NEW security system installation, I can provide the estimate to a new customer or an existing customer (existing customer, but a new location for them). When it is an existing customer, I have a drop down box that lists all existing customers (ALL RECORDS in the customer table).
THIS is where I want all the records to be ordered properly. As it is now, I get a jumbled mess of hundreds of records making it brutal to find the existing owner.
Hopefully this helps with what I'm trying to achieve.
You can create a custom manager, which will do what you want.
class CompanyFilter(models.Manager):
def get_query_set(self):
qs = super(CompanyFilter, self).get_query_set()
return qs.filter(is_company=True).order_by('company_name')
class PersonFilter(models.Manager):
def get_query_set(self):
qs = super(PersonFilter, self).get_query_set()
return qs.filter(is_company=False).order_by('last_name')
class Contact(models.Model):
# ... your regular fields
companies = CompanyFilter()
people = PersonFilter()
all_companies = Contact.companies.all()
all_people = Contact.people.all()
all_contacts = Contact.objects.all()
1 . assuming that either of the fields is always NULL you can use extra query:
MyModel.objects
.extra(select=dict(name='coalesce(last_name, company_name)'))
.order_by('name')
(COALESCE seems to be supported in all major database engines)
2 . or simply eliminate either last_name or company_name and put last names and company names in to the same field and sort by it.
Related
I have the following Models of customer details with each customers having different payment modes (eg. cash, online transfer, etc...) :
class Customer(models.Model):
#some customer details
class Payment(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.RESTRICT, related_name='payments')
payment_mode = models.CharField(max_length=255, blank=True, null=True)
And I would like to add a new Invoice Model to include the customer as well as the customer's payment modes.
class Invoice (models.Model):
customer = models.ForeignKey(Customer, on_delete=models.RESTRICT, related_name='payments')
payment_mode = models.ForeignKey(Customer.payments.payment_mode, on_delete=models.RESTRICT)
I am going to create an Invoice for a customer and will input the customer's available payment mode. But the the invoice's payment mode is giving me an AttributeError: 'ReverseManyToOneDescriptor' object has no attribute 'payment_mode'.
May I know how do I set up the reference to the customer's child data?
Thank you.
What you have is not a valid field definition.
You can reference Payment directly
payment_mode = models.ForeignKey(Payment, on_delete=models.RESTRICT)
Why is the Invoice model even required? You have the same fields already in the existing models.
You can simply make a view to do this.
For example,
def show_invoice(request, pk):
# this pk value should be sent by your frontend and represents your Primary Key value for the current customer
customer = Customer.objects.get(pk=pk)
return render(request, 'some_html_page.html', {'customer': customer})
Now in your some_html_page.html, you can show the details you want using the 'context' to the render function ({'customer': customer}) we just passed.
Models in Django should be thought of as Tables in SQL; you are not supposed to make a new one every time you want to "infer" something, rather you should make them when you want to 'store' something (or normalize existing tables/models). The Invoice model does not do either of these two things.
You can give this a read to understand how to write views in Django this.
In the case where you really want to make an Invoice model you don't need to make a payment_mode field, since you're already pointing to the Customer model which is, in turn, pointing to the Payment model.
I have a model of teacher and student . If I created a Student and again create a teacher with same name and email and stuffs, It gets created .. Can't be a teacher and student of same people in a college. How to apply in rest api?
There are several way to solve this, depending on your requirements and preference.
One way would be at database level with constraints. In this case you'd have to create model with all people regardless of their status and add additional boolean field that differentiates between Students and Teachers. This would look like this:
class People(models.Model):
email = models.EmailField(unique=True)
is_teacher = models.BooleanField()
unique means that email must be unique throughout the table and if you try to add another person with the same email, IntegrityError will be raised.
There is also a possibility to use unique over several fields with unique_together like this.
class People(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
class Meta:
unique_together = (('first_name', 'last_name'),)
This means that first_name and last_name together must be unique.
Another approach would be to check if student or teacher is already in one or the other table before saving with filter() and exists().
teacher_exists = Teacher.objects.filter(teacher=something).exists()
student_exists = Teacher.objects.filter(student=something).exists()
exists() returns True if the QuerySet contains any results, and False if not.
I can't find how to achieve the following:
Say you have two models:
Candidates (first_name, last_name, brith_date)
Developers (first_name, last_name, birth_date, team_name, salary, ...)
Candidates are recruited by an external company. Each morning they refresh a csv-file listing the data of all active candidates. There also is a cron job to sync the csv-file to the Django Candidates model.
Now, when an admin wants to add a new Developer to a team, he should be able to:
Select a Candidate from the Candidate model and 'copy' the personal data into the Developer table. Team_name, salary and other fields are added manually
When a developer is recruited not via the external recruiting company, the Admin should be able to add the personal info manually.
I could reference Candidate one-on-one in the Developers model, but this has the disadvantage that the Candidate list also has the active developers in it, and therefore can not be synced to the recruiters csv file. I would prefer just to optionally copy the personal data from the Candidates model to the Developers model, or add them manually.
Any ideas on how to do this would be greatly appreciated!
This is ideal for multi-table inheritance.
Example:
class Person(models.Model):
first_name = models.CharField(max_length=32)
last_name = models.CharField(max_length=64)
dob = models.DateField()
class CandidateManager(models.Manager):
def get_queryset(self):
return super(CandidateManager, self).get_queryset().filter(
is_hired=False
)
class Candidate(Person):
cv = models.TextField()
is_hired = models.BooleanField(default=False, editable=False)
objects = CandidateManager()
def hire(self, update=False):
self.is_hired = True
if update:
self.save(update_fields=['is_hired'])
class DeveloperManager(models.Manager):
def get_queryset(self):
return super(DeveloperManager, self).get_queryset().filter(
is_hired=True
)
class Developer(Candidate):
team_name = models.CharField(max_length=32)
objects = DeveloperManager()
As you can see it pretty much writes itself and you can either write a custom AdminAction to do this in the Django backend, or write a view for it.
I have two Models in Django. The first has the hierarchy of what job functions (positions) report to which other positions, and the second is people and what job function they hold.
class PositionHierarchy(model.Model):
pcn = models.CharField(max_length=50)
title = models.CharField(max_length=100)
level = models.CharField(max_length=25)
report_to = models.ForeignKey('PositionHierachy', null=True)
class Person(model.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
...
position = models.ForeignKey(PositionHierarchy)
When I have a Person record and I want to find the person's manager, I have to do
manager = person.position.report_to.person_set.all()[0]
# Can't use .first() because we haven't upgraded to 1.6 yet
If I'm getting people with a QuerySet, I can join (and avoid a second trip to the database) with position and report_to using Person.objects.select_related('position', 'position__reports_to').filter(...), but is there any way to avoid making another trip to the database to get the person_set? I tried adding 'position__reports_to__person_set' or just position__reports_to__person to the select_related, but that doesn't seem to change the query. Is this what prefetch_related is for?
I'd like to make a custom manager so that when I do a query to get Person records, I also get their PositionHeirarchy and their manager's Person record without more round trips to the database. This is what I have so far:
class PersonWithManagerManager(models.Manager):
def get_query_set(self):
qs = super(PersonWithManagerManager, self).get_query_set()
return qs.select_related(
'position',
'position__reports_to',
).prefetch_related(
)
Yes, that is what prefetch_related() is for. It will require an additional query, but the idea is that it will get all of the related information at once, instead of once per Person.
In your case:
qs.select_related('position__report_to')
.prefetch_related('position__report_to__person_set')
should require two queries, regardless of the number of Persons in the original query set.
Compare this example from the documentation:
>>> Restaurant.objects.select_related('best_pizza')
.prefetch_related('best_pizza__toppings')
Can someone give me the best approach with an example for the following...
On a page I load the 'Group' object by ID. I also want to list all contacts that belong to that group (with paging).
Because of the paging issue I was thinking of just running a second database query with...
In my view...
group = get_object_or_404(Group, pk=id)
contacts = Contacts.objects.filter(group=x)
But this seems wasteful as I'm already getting the Group why hit the database twice.
See my model.
class GroupManager(models.Manager):
def for_user(self, user):
return self.get_query_set().filter(user=user,)
class Group(models.Model):
name = models.CharField(max_length=60)
modified = models.DateTimeField(null=True, auto_now=True,)
#FK
user = models.ForeignKey(User, related_name="user")
objects = GroupManager()
def get_absolute_url(self):
return reverse('contacts.views.group', args=[str(self.id)])
class Contact(models.Model):
first_name = models.CharField(max_length=60)
last_name = models.CharField(max_length=60)
#FK
group = models.ForeignKey(Group)
This is what select_related is designed for:
Returns a QuerySet that will automatically “follow” foreign-key
relationships, selecting that additional related-object data when it
executes its query. This is a performance booster which results in
(sometimes much) larger queries but means later use of foreign-key
relationships won’t require database queries.
In your case it would be:
Group.objects.select_related().get(pk=group)
Now on each FK lookup, you won't hit the database again.
The next step would be to cache the results using the cache api so that you don't hit the database everytime the next "page" is called. This would be useful if your data isn't time sensitive.