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.
Related
Given the following model that stores the user's wish list for reading books:
class ReadingList(models.Model):
user_id = models.ForeignKey(UserInfo, on_delete=models.DO_NOTHING, null=False, blank=False, default=None, db_column='user_id')
book= models.CharField(max_length=255, blank=False)
creation_time = models.DateTimeField(blank=True)
class Meta:
unique_together = (('user_id', book),)
I want to create a model that helps in tracking the time spent in the reading the book on different days which looks something like this:
class ReadingTracker(models.Model):
user_id = models.ForeignKey(ReadingList, on_delete=models.DO_NOTHING, related_name='user', blank=False, db_column='user_id')
book= models.ForeignKey(ReadingList, on_delete=models.DO_NOTHING, related_name='book-to-read', blank=False, db_column='book')
time = models.DateTimeField(blank=True)
time_spent = models.floatfield()
On the client-side (corresponding to ReadingTracker) for both the fields user_id and book
I see that ReadingList object (1), ReadingList object (2), ... are listed. But, this is not working as expected.
What I want to achieve are the following:
For user_id field I want to see the something like dummy_uid1, dummy_uid2, ... to be listed.
Consider dummy_uid1 wants to read book1 and book2 whereas dummy_uid2 wants to read book1 and book3.
When dummy_uid1 is selected as user_id, I want only book1 and book2 to be listed for selection.
How do I define the model in django rest framework to achieve this?
Any suggestions related to the above would be much appreciated and thank you in advance.
There are two parts to this question:
If you want to see a different value than ReadingList object (1) then you need to define the __str__ value of your model, you can do this like so:
class ReadingList(models.Model):
...
def __str__(self):
return f'{self.user_id}' # return whatever string you want to display
If you want to just display the books for a particular user then you can use a filter() (see the Django documentation):
reading_list = ReadingList.objects.get(...)
ReadingTracker.objects.filter(user_id=reading_list)
However, I would add that you have a user_id on your ReadingList object which does seem to connect to a User model, but your user_id on ReadingTracker is a ForeignKey relation to ReadingList, which is confusing. I would suggest renaming the field or actually making it link to the User model (though this is unnecessary as you can still filter by User through the ReadingList model).
In my primary class model Deals, I have certain fields as description, price, date_created etc. I now have to add some fields having sub-fields to it. For eg, I'm trying to add an age field to Deals. This age field further has subfields (like score_for_kid, score_for_baby, score_for_old etc), and I want to edit these scores from the admin.
Here is my models.py:
class Deals(models.Model):
description = models.TextField()
price = models.DecimalField(max_digits=7, decimal_places=2)
url = models.URLField(verify_exists=False)
currency = models.CharField(max_length=3)
created_date = models.DateField(auto_now_add=True)
kid_score = models.IntegerField(max_length=2,default=0)
teenager_score = models.IntegerField(max_length=2,default=0)
youth_score = models.IntegerField(max_length=2,default=0)
old_score = models.IntegerField(max_length=2,default=0)
I don't want to store all these sub fields (around 20-25 in 4 different fields) in the model, instead an age field connected to these subfields. Would a ManyToManyField work for this?
The underlying requirement is that when a user selects a subfield (say kids) on the browser, all the objects having higher kid scores are displayed.
I'm very new to Django and any help on this would be great. Thanks.
If I understand your question properly ou need to use ForeignKey fields.
class Deals(models.Model):
description = models.TextField()
price = models.DecimalField(max_digits=7, decimal_places=2)
#...
age = models.ForeignKey(Age)
class Age(models.Model):
kid_score = models.IntegerField(max_length=2,default=0)
teenager_score = models.IntegerField(max_length=2,default=0)
#...
Have a good read of the docs on Models. You might also find it useful to do some reading on relational databases / basic sql.
When you come to edit your objects in the django admin, you'll probably want to use an InlineModelAdmin class.
UPDATE
re-reading your question, it sounds like you might simply want to show / hide these additional fields on the main Deal model. If this is the case then you want to use fieldsets in the admin, with a class 'collapse'. There's an example in the docs.
If you want each Deal record to have multiple kid_score's associated with it then you want a foreign key. If each Deal can only have one kid_score then you need to keep the kid_score (and other) fields in the main model (if this is confusing then definitely do some reading on sql / relational databases).
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.
In my model I have a table for users (who are students or instructors - I have a UserProfile table that is connected to auth.User), a table for courses, and a table called enrollment, which records which students are enrolled in which courses. My models.py is as follows:
class Course(models.Model):
name = models.CharField(max_length=40)
instructor = models.ForeignKey(UserProfile, related_name="Instructor")
students = models.ManyToManyField(UserProfile, through='Enrollment')
class UserProfile(models.Model):
user = models.OneToOneField(User, primary_key=True)
role = models.CharField(max_length=4, choices=ROLE_CHOICES) # 'stud' or 'inst'
class Enrollment(models.Model):
course = models.ForeignKey(Course)
student = models.ForeignKey(UserProfile)
For a given User, I would like to find all the courses s/he is enrolled in. How can I do this?
Also, where can I find a thorough explanation of how to do queries in Django, preferably with lots of examples that slowly increase in complexity?
If you have a UserProfile instance user_profile, then try:
courses = Course.objects.filter(students=user_profile)
if you have a User instance user, then you can use double underscore notation.
courses = Course.objects.filter(students__user=user)
For an explanation, I would start with the django docs for Making queries. Other people might have some other suggestions.
As an aside: in this case, unless you are using a legacy db, you don't really need to explicitly define the joining table Enrollment, as you haven't defined any extra fields.
If instead of a User instance you have the username field from the User instance you could do the following:
courses = Course.objects.filter(students__user__username='thespecificusername')
The scenario you're constructing is very similar to the one discussed here: https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships
ists,
I'm looking for some validation on a subclassing approach. I have the following:
class Person(models.Model):
"""
Basic person
"""
user = models.ForeignKey(User) # hide
first_name = models.CharField(max_length=200)
last_name = models.CharField(blank=True, max_length=200)
class Meta:
verbose_name_plural = "People"
def __unicode__(self):
return u"%s, (%s)" % (self.first_name, self.user)
class Contributor(Person):
"""
Contributor
A Core contributor of the site content workflow
"""
class Meta:
verbose_name = 'contributor'
verbose_name_plural = 'contributors'
def get_articles(self):
"""
Return the articles that the author has published.
"""
return Article.objects.filter(self_in=authors)
class Member(Person):
"""
Member
A Member of the website.
"""
# Member history, payments etc...
joined = models.DateTimeField()
So, each Member or Contributor is a Person within the system, but it is possible for a Person to be 'None', 1 or both Member & Contributor, depending on their context.
This subclassing approach makes it simple to do things like:
#...
contributors = models.ManyToManyField(Contributor, help_text="Contributors/Authors to this article")
or
print Member.objects.all()
... and of course the usual efficiencies of subclassing, i.e. common fields and methods.
However, I'm wondering about the pros & cons of doing something like
class Person(models.Model):
"""
Person
"""
user = models.ForeignKey(User) # hide
first_name = models.CharField(max_length=200)
last_name = models.CharField(blank=True, max_length=200)
is_contributor = models.BooleanField()
is_member = models.BooleanField()
but then needing to filter things like
# Assuming this is possible...
contributors = models.ManyToManyField(Person.objects.filter(is_contributor=True), help_text="Contributors/Authors to this article")
With the subclassing approach, I wonder about the challenges of being aware of users that are People (Person), Members or Contributors - and being able to discern between.
i.e. its really easy to do if person.is_contributor: but perhaps more challenging
try:
Contributor.objects.get(person__user_id=request.user.id)
except:
no_access()
else:
let_them_in()
Apologies for the open-endness of this question -- it may have been more an opportunity to think out aloud.
First, there are two oddities about your model to begin with:
1) Why is Person -=> User a ForeignKey and not a OneToOne? Might a user be more than one person?
2) User already has first and last names - why also assign them to person?
Next, to the extent that your ultimate goal is the authorization depicted at the end, why not just use permissions? Then you won't need the boolean fields or the try - except at the end.
Fundamentally, I see nothing wrong with subclassing the User model. Folks in #django often fight over this, but if done right, it is one of the most time-saving and powerful steps you can take when you first sit down with your new django project.
Adding different subclasses of User with different attributes and different methods can very quickly give you a robust user environment with enormous auth possibilities. Thus far, however, it doesn't look like you have done anything that requires you to subclass User.