Haystack searching multiple fields - django

I am currently building a page in django, where there are 4 form fields, 2 text, 2 select fields, and when submitted it takes those fields and searches several models for matchinng items.
the model looks like this:
class Person(models.Model):
user = models.ForeignKey(User, blank=True, null=True, verbose_name="the user associated with this profile")
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
about = models.TextField(max_length=255, blank=True, null=True)
birthdate = models.DateField(blank=True, null=True, verbose_name="Birthdate (yyyy-mm-dd)")
GENDER_CHOICES = (
(u'M', u'Male'),
(u'F', u'Female'),
)
gender = models.CharField(max_length=1, choices = GENDER_CHOICES, default = 'M')
picture = models.ImageField(upload_to='profile', blank=True, null=True)
nationality = CountryField(blank=True, null=True)
location = models.CharField(max_length=255, blank=True, null=True)
command_cert = models.BooleanField(verbose_name="COMMAND certification")
experience = models.ManyToManyField('userProfile.MartialArt', blank=True, null=True)
and I am trying to search the first_name field, the last_name field, the nationality field, and the experience field, but say if the first_name field is blank, I need to pass an empty value so it returns all rows, then filter from there with last name the same way, for some reason it is not working at all for me. this is my sqs:
results = SearchQuerySet().models(Person).filter(first_name=sname, last_name=slastname, nationality=scountry, experience__pk=sexperience)
any ideas?

Without seeing specific errors or a stack trace, it's hard to determine what "is not working at all".
Edit: Looking at your provided view code, I would remove the filter and return all of the objects for your Fighter, Referee, Insider, and Judge models. This is to ensure that the issue here lies in the filter, and not something else.
Then, once I'd verified that objects are being placed into results, I'd put in the filters one at a time to determine what the problematic filter is. Give this a try and reply back with your results.

Related

Django Forms multiple foreignkey

I have four models, three of which have ‘independent’ fields but the fourth models has ForeignKey links to the other three.
class PreCheck(models.Model):
name = models.CharField(max_length=120)
time_in = models.DateTimeField(auto_now_add=True)
is_insured = models.BooleanField()
class MainCheck(models.Model):
height = models.FloatField()
weight = models.IntegerField()
class PostCheck(models.Model):
sickness = models.CharField(max_length=30)
medication = models.CharField(max_length=30)
class MedicalRecord(models.Model):
patient = models.ForeignKey(User)
next_check_date = models.DateTimeField()
payment_amount = models.IntegerField()
initial_check = models.ForeignKey(PreCheck)
main_check = models.ForeignKey(MainCheck)
post_check = models.ForeignKey(PostCheck)
Assume a patient goes in a room, a precheck is done and saved, then other checks are done and finally a final record is set.
Ideally, I would like to fill in forms for the different models at different times possibly in different pages/tabs.
The admin has popups for the MedicalRecord model but in the frontend its hard to write javascript for that.
Another option would be to fill in the modelforms separately and do a str return function then select that from dropdowns in the MedicalRecord form( which I’m trying to avoid)
Just add blank=True, null=True for each ForeignKey fields.
initial_check = models.ForeignKey(PreCheck, blank=True, null=True)
main_check = models.ForeignKey(MainCheck, blank=True, null=True)
post_check = models.ForeignKey(PostCheck, blank=True, null=True)
at the initial check, you can create MedicalRecord with help of MedicalRecord model-form, this time main_check and post_check record can be left blank.
after main check, you can update MedicalRecord with main_check details, this time left blank post_check record, and keep updating your MedicalRecord on different pages/tabs with available details.

Django Many to Many Data Duplication?

Background
I'm storing data about researchers. eg, researcher profiles, metrics for each researcher, journals they published in, papers they have, etc.
The Problem
My current database design is this:
Each Researcher has many journals (they published in). The journals have information about it.
Likewise for Subject Areas
But currently, this leads to massive data duplication. Eg, the same journal can appear many times in the Journal table, just linked to a different researcher, etc.
Is there any better way to tackle this problem? Like right now, I have over 5000 rows in the journal column but only about 1000 journals.
Thank you!
EDIT: This is likely due to the way im saving the models for new data (mentioned below). Could anyone provide the proper way to loop and save hashes to models?
Model - Researcher
class Researcher(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
scopus_id = models.BigIntegerField(db_index=True) # Index to make searches quicker
academic_rank = models.CharField(max_length=100)
title = models.CharField(max_length=200,default=None, blank=True, null=True)
salutation = models.CharField(max_length=200,default=None, blank=True, null=True)
scopus_first_name = models.CharField(max_length=100)
scopus_last_name = models.CharField(max_length=100)
affiliation = models.CharField(default=None, blank=True, null=True,max_length = 255)
department = models.CharField(default=None, blank=True, null=True,max_length = 255)
email = models.EmailField(default=None, blank=True, null=True)
properties = JSONField(default=dict)
def __str__(self):
return "{} {}, Scopus ID {}".format(self.scopus_first_name,self.scopus_last_name,self.scopus_id)
Model - Journal
class Journal(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
researchers = models.ManyToManyField(Researcher)
title = models.TextField()
journal_type = models.CharField(max_length=40,default=None,blank=True, null=True)
abbreviation = models.TextField(default=None, blank=True, null=True)
issn = models.CharField(max_length=50, default=None, blank=True, null=True)
journal_rank = models.IntegerField(default=None, blank=True, null=True)
properties = JSONField(default=dict)
def __str__(self):
return self.title
How I'm currently saving them:
db_model_fields = {'abbreviation': 'Front. Artif. Intell. Appl.',
'issn': '09226389',
'journal_type': 'k',
'researchers': <Researcher: x, Scopus ID f>,
'title': 'Frontiers in Artificial Intelligence and Applications'}
# remove researchers or else create will fail (some id need to exist error)
researcher = db_model_fields["researchers"]
del db_model_fields["researchers"]
model_obj = Journal(**db_model_fields)
model_obj.save()
model_obj.researchers.add(researcher)
model_obj.save()
Here is how it works :
class Journal(models.Model):
# some fields
class Researcher(models.Model):
# some fields
journal = models.ManyToManyField(Journal)
Django gonna create a relation table :
Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship
So you'll have many rows in this table, which is how it works, but journal instance and researcher instance in THEIR table will be unique.
Your error is maybe coming from how you save. Instead of :
model_obj = Journal(**db_model_fields)
model_obj.save()
Try to just do this:
model_obj = Journal.objects.get_or_create(journal_id)
This way you'll get it if it already exists. As none of your fields are unique, you're creating new journal but there's no problem cause django is generating unique ID each time you add a new journal.

Django: Get distinct values from a foreign key model

Django newbie, so if this is super straightfoward I apologize.
I am attempting to get a listing of distinct "Name" values from a listing of "Activity"s for a given "Person".
Models setup as below
class Activity(models.Model):
Visit = models.ForeignKey(Visit)
Person = models.ForeignKey(Person)
Provider = models.ForeignKey(Provider)
ActivityType = models.ForeignKey(ActivityType)
Time_Spent = models.IntegerField(blank=True, null=True)
Repetitions = models.CharField(max_length=20, blank=True, null=True)
Weight_Resistance = models.CharField(max_length=50, blank=True, null=True)
Notes = models.CharField(max_length=500, blank=True, null=True)
class ActivityType(models.Model):
Name = models.CharField(max_length=100)
Activity_Category = models.CharField(max_length=40, choices=Activity_Category_Choices)
Location_Category = models.CharField(max_length=30, blank=True, null=True, choices=Location_Category_Choices)
I can get a listing of all activities done with a given Person
person = Person.objects.get(id=person_id)
activity_list = person.activity_set.all()
I get a list of all activities for that person, no problem.
What I can't sort out is how to generate a list of distinct/unique Activity_Types found in person.activity_set.all()
person.activity_set.values('ActivityType').distinct()
only returns a dictionary with
{'ActivityType':<activitytype.id>}
I can't sort out how to get straight to the name attribute on ActivityType
This is pretty straightforward in plain ol' SQL, so I know my lack of groking the ORM is to blame.
Thanks.
Update: I have this working, sort of, but this CAN'T be the right way(tm) to do this..
distinct_activities = person.activity_set.values('ActivityType').distinct()
uniquelist = []
for x in distinct_activities:
valuetofind = x['ActivityType']
activitytype = ActivityType.objects.get(id=valuetofind)
name = activitytype.Name
uniquelist.append((valuetofind, name))
And then iterate over that uniquelist...
This has to be wrong...
unique_names = ActivityType.objects.filter(
id__in=Activity.objects.filter(person=your_person).values_list('ActivityType__id', flat=True).distinct().values_list('Name', flat=True).distinct()
This should do the trick. There will be not a lot of db hits also.
Writing that down from my phone, so care for typos.

Django ModelForm or Form

i am totally new to both Python and Django,so please excuse me if this question is a bit simpleton.
I am writing a small app to track the scores of a Billiards match. I don't need to explain all the details, but the basic objects involved are:
Team has Players
Match is between two Teams (home and away)
Match has a collection of Games.
Each Game is between two Players (one from each team), excluding players who have already played in the Match.
I have made the following models:
class Team(models.Model):
team_id = models.IntegerField(unique=True, max_length=5, blank=False,validators=[validate_five_digits])
name = models.CharField(max_length=50, blank=False, null=False)
class Player(models.Model):
id = models.IntegerField(unique=True, max_length=5, blank=False,validators=[validate_five_digits])
team = models.ForeignKey(Team, blank=True, null=True)
first_name = models.CharField(max_length=50, blank=False, null=False)
last_name = models.CharField(max_length=50, blank=False, null=False)
alias_name = models.CharField(max_length=50, blank=True, null=True)
current_handicap = models.IntegerField()
class Match(models.Model):
date = models.DateField(blank=False, null=False)
location = models.CharField(max_length=255, blank=True, null=True)
table_size = models.CharField(max_length=50, blank=True, null=True)
home_team = models.ForeignKey(Team, related_name='home_team', blank=True, null=True)
away_team = models.ForeignKey(Team, related_name='away_team', blank=True, null=True)
class Game(models.Model):
match = models.ForeignKey(Match, blank=False, null=False)
match_sequence = models.IntegerField(blank=True, null=True)
player1 = models.ForeignKey(Player,related_name='player1', blank=False, null=False)
player2 = models.ForeignKey(Player,related_name='player2', blank=False, null=False)
player1_handicap = models.IntegerField(null=True, blank=True)
player2_handicap = models.IntegerField(null=True, blank=True)
I have successfully made Views and ModelForms to add/edit Teams, Players and Matches.
The list of Matches is displayed in a table, with 1 match per row....and now I want to put a button to add a new Game.
My plan is to do so by having the button go to a url that looks like this:
game/new/?match_id=1 (or something like that)
Now for the part where i am confused.....When you go to add a new game, i want to display 3 choice fields, and only 3 choice fields.
First Choice field should display Players from Home Team that have not yet played a game in this match
Second Choice field should display Players from Away Team that have not yet played a game in the match
Third Choice Field would only have two choices (Home and Away)....and would indicate which player gets to shoot first.
Then, when user clicks Submit it needs to create a Game() object with the match_id from the query string, the next sequence number for the match, and Player1 = either home or away player, based on 3rd choice field.
I am totally confused about how this should be done....should i be using a forms.Form or a ModelForm?
Any suggestions or skeleton code to clue me in?
Thanks in advance for help with such a newbie question!
Paul
What type of form class to use when building a Django app is a simple problem. If you're editing a model, use a ModelForm, otherwise use a Form.
If you need to limit choices or alter choices based on other data, you can still do that with a ModelForm by overriding the form's __init__()
Using a ModelForm will reduce the amount of code necessary to add the Game instance, because a ModelForm already knows how to create or update an instance of Game. You'd have to handle that yourself if you were just using a Form class.

django prefetch_related not working

I am trying to export all my database with a prefetch_related but I only get data from the main model.
My models:
class GvtCompoModel(models.Model):
gvtCompo= models.CharField(max_length=1000, blank=False, null=False)
...
class ActsIdsModel(models.Model):
year = models.IntegerField(max_length=4, blank=False, null=False)
...
class RespProposModel(models.Model):
respPropos=models.CharField(max_length=50, unique=True)
nationResp = models.ForeignKey('NationRespModel', blank=True, null=True, default=None)
nationalPartyResp = models.ForeignKey('NationalPartyRespModel', blank=True, null=True, default=None)
euGroupResp = models.ForeignKey('EUGroupRespModel', blank=True, null=True, default=None)
class ActsInfoModel(models.Model):
#id of the act
actId = models.OneToOneField(ActsIdsModel, primary_key=True)
respProposId1=models.ForeignKey('RespProposModel', related_name='respProposId1', blank=True, null=True, default=None)
respProposId2=models.ForeignKey('RespProposModel', related_name='respProposId2', blank=True, null=True, default=None)
respProposId3=models.ForeignKey('RespProposModel', related_name='respProposId3', blank=True, null=True, default=None)
gvtCompo= models.ManyToManyField(GvtCompoModel)
My view:
dumpDB=ActsInfoModel.objects.all().prefetch_related("actId", "respProposId1", "respProposId2", "respProposId3", "gvtCompo")
for act in dumpDB.values():
for field in act:
print "dumpDB field", field
When I display "field", I see the fields from ActsInfoModel ONLY, the starting model. Is it normal?
You haven't understood the arguments to prefetch_related. It's not a list of fields, but a list of models.
(Note that your field naming convention is also very misleading - respProposId1 and actId are not IDs, but actual instances of the models. Django has created an underlying field in each case by appending _id, so the db columns are respProposId1_id and actId_id. You should just call the fields resp_propos1 and resp_propos2 - also note that normal style is lower_case_with_underscore, not capWords.)
It is normal, that you are seeing fields from ActsInfoModel only. You can access related models via dot notation, like:
acts = ActsInfoModel.objects.all().prefetch_related("actId", "respProposId1", "respProposId2", "respProposId3", "gvtCompo")
for act in acts:
print act.respProposId1.respPropos
Related models are already prefetched, so it won't produce any additional queries. FYI, quote from docs:
Returns a QuerySet that will automatically retrieve, in a single
batch, related objects for each of the specified lookups.