Django model field relating to a few models - django

Imagine a 5x5 grid (map), every field of it represents a certain object (it can be a monster, a tree etc.)
So, here we have:
class Field(Model):
x = y = PositiveIntegerField()
content = ...(?)
Here the problem arises. Here is the alternative, but I think this way is too messy, especially if I have many different content ids.
class Field(Model):
x = y = PositiveIntegerField()
content = PositiveIntegerField()
monster_rel = ForeignKey(Monster, null=True, blank=True)
building_rel = ForeignKey(Monster, null=True, blank=True)
nature_obj_rel = ForeignKey(Monster, null=True, blank=True)
and then in a view:
f = Field.objects.get(pk=1)
if f.content == 1:
print "Monster %s of level %d" % (f.monster_rel.name, f.monster_rel.level)
elif f.content == 2:
print "This is a %s" % f.building_rel.type
...
Is there a better solution for this?
EDIT
I would like fields like:
content_id = IntegerField()
content_rel = FieldRelatedToModelByContentId()

Well, sounds like generic relations is exactly what you're looking for.

Related

How to order a queryset result by the number of entries in a manytomanyfield?

Let's say that i have this queryset :
result_list = []
get_result_list = [x for x in search_text_imported.split() if len(x) > 2]
for keyword in get_result_list:
result_list += list(Node.objects.filter((Q(name__icontains=keyword) | Q(Tags__icontains=keyword)), tree_type='root', tunisia_office=True, published=True ).order_by('-bookmarked_by'))
result = list(OrderedDict.fromkeys(result_list))
models.py
class Node(MPTTModel):
name = models.TextField(blank=True, null=True)
bookmarked_by = models.ManyToManyField(CustomUser, null=True, blank=True)
I want to show first the objects that have the most number of entries in the bookmarked_by field.
Is there a way to do it ?
Any help is appreciated.
Use the aggregate function Count
from django.db.models import Count
Node.objects.annotate(
num_bookmarks=Count('bookmarked_by')
).order_by('-num_bookmarks')
https://docs.djangoproject.com/en/2.2/topics/db/aggregation/#aggregation

Django Update Multiple Object error

i found some problem when i try to update multiple object in my models. here is my models:
class NumberSequence(models.Model):
code = models.CharField(max_length=12)
name = models.CharField(max_length=60)
prefix = models.CharField(max_length=3)
length = models.IntegerField()
last = models.IntegerField(verbose_name='Last Number Used')
def getNumberSequence():
ns = NumberSequence.objects.filter(code='REQ')
letter = ns[0].prefix
lastNumber = ns[0].last+1
l = '{0}-{1:0'+str(ns[0].length)+'d}'
for num in ns:
num.last = lastNumber
num.save()
return l.format(letter,lastNumber+1)
class Requisitions(models.Model):
number = models.CharField(max_length=20, default=getNumberSequence())
transDate = models.DateField(verbose_name='Date')
businessUnit = models.ForeignKey(BusinessUnit, verbose_name='Unit')
division = models.ForeignKey(Division, verbose_name='Division')
remarks = models.TextField
status = models.IntegerField(verbose_name='Status')
when i create new record in Requisition, the table Number Sequence does not update. but if i restart the service, the number sequence table updated automatically.
what's happened with my code?
any suggestion, please..
You should not call the default function in your field definition, but pass the callable only without parentheses.
number = models.CharField(max_length=20, default=getNumberSequence)

Django queryset search on multiple models, return the same object

I'm trying to create an advanced search on my website, you are looking at various models related to each one, always returning a list of profiles that meet some parameters
Here are my Models:
class Profile(models.Model):
first_name=models.CharField(max_length=60, blank=False)
last_name=models.CharField(max_length=60, blank=False)
residence=models.CharField(max_length=60, null=True, blank=True)
birthdate=models.DateField(null=True, blank=True)
telephone=models.CharField(max_length=60, null=True, blank=True)
email=models.EmailField(null=True, blank=True)
linkedin=models.URLField(null=True, blank=True)
starred=models.BooleanField(default=False)
created_from = models.ForeignKey(EmployeeUser, related_name='profile_author')
created_on = models.DateField(default=tznow)
internal_id = models.CharField(max_length=5, blank=True)
class Education(models.Model):
almalaurea_id = models.CharField(max_length=60, null=True, blank=True)
profile = models.ForeignKey(Profile, related_name='education_profile')
education_type = models.ForeignKey(Education_type, related_name='education_type')
class Education_type(models.Model):
VALUES = (
(0, 'Altro'),
(1, 'Licenza media'),
(2, 'Diploma'),
(3, 'Laurea Triennale'),
(4, 'Laurea Magistrale'),
)
title = models.CharField(max_length=60)
value = models.IntegerField(choices=VALUES)
I want to search the profiles that meet various results, such as birthdate, residence, starred, education (based on education_type)
This is an example scenario, my research includes other models
These are the research in my view, I thought that having found the results of the two queries, I could extract the profile id and compare them, then run another query by selecting profiles that match, but I think it's not a great idea, the real scenario includes other various models.
filters_profile = []
filters_education = []
year = form.cleaned_data["year"]
residence = form.cleaned_data["residence"]
starred = form.cleaned_data["starred"]
education_type = form.cleaned_data["education_type"]
if year:
filters_profile.append(Q(birthdate__year=year))
if residence:
filters_profile.append(Q(residence__icontains=residence))
if starred:
filters_profile.append(Q(starred=starred))
result_profile = Profile.objects.filter(reduce(lambda q1, q2: q1 & q2, filters_profile)).order_by('first_name')
result_education = None
if education_type:
e = Education_type.objects.filter(title=education_type)
result_education = Education.objects.filter(education_type=e).prefetch_related('profile','education_type')
Any idea?
Many thanks in advance :)
EDIT :
About the solution of #Geo Jacob
Here is the third models:
if valutation:
result_valutation = Status.objects.filter(valutation=valutation).values_list('profile_id', flat=True)
key['id__in'] = result_valutation
Adding this code for my scenario, this solution don't work, as i written in the comments :)
"in practice, the content of key['id__in'] is overwritten when the other model query (this) is executed"
Try this:
key = {}
year = form.cleaned_data["year"]
residence = form.cleaned_data["residence"]
starred = form.cleaned_data["starred"]
education_type = form.cleaned_data["education_type"]
if year:
key['birthdate__year'] = year
if residence:
key['residence__icontains'] = residence
if starred:
key['starred'] = starred
if education_type:
e = Education_type.objects.filter(title=education_type)
result_education = Education.objects.filter(education_type=e).values_list('profile_id', flat=True)
key['id__in'] = result_education
result_profile = Profile.objects.filter(**key).order_by('first_name')
My solution working on more than 2 models, based on #Geo Jacob solution, thank you
I make a check and put in key['id__in'] only matched id from the previous query, so as to intersect the results
key = {}
statokey = 0
year = form.cleaned_data["year"]
residence = form.cleaned_data["residence"]
starred = form.cleaned_data["starred"]
education_type = form.cleaned_data["education_type"]
valutation = form.cleaned_data["valutation"]
if year:
key['birthdate__year'] = year
if residence:
key['residence__icontains'] = residence
if starred:
key['starred'] = starred
if education_type:
e = Education_type.objects.filter(title=education_type)
result_education = Education.objects.filter(education_type=e).values_list('profile_id', flat=True)
if statokey > 0:
for r in result_education:
for k in key['id__in']:
if r == k:
key['id__in'] = str(r)
else:
key['id__in'] = result_education
statokey += 1
if valutation:
result_valutation = Status.objects.filter(valutation=valutation).values_list('profile_id', flat=True)
if statokey > 0:
for r in result_valutation:
for k in key['id__in']:
if r == k:
key['id__in'] = str(r)
else:
key['id__in'] = result_valutation
statokey += 1
result_profile = Profile.objects.filter(**key).order_by('first_name')

Django aggregate with associated values

I have a models.py like so:
class ScoreCard(models.Model):
user = models.ForeignKey(User)
course = models.ForeignKey(Course)
created = models.DateTimeField(default=datetime.now)
score = models.IntegerField()
holes = models.IntegerField(
default=9
)
handicap = models.IntegerField(default=0)
class UserProfile(User):
...
def get_nine_stats(self, course):
nine_stats = ScoreCard.objects.filter(course=course) \
.filter(holes=9) \
.aggregate(Avg('score'), Max('score'), Min('score'))
return nine_stats
This is fine and returns almost what I need - a dict of max, min and avg. However, I really want those values with the associated created fields. Is this possible using the aggregate method?

How to declare and call a model method navigating through relations in django?

I Have 3 models
class Room(models.Model):
house = models.ForeignKey('Property', related_name='rooms')
beds = models.IntegerField(max_length=10)
class Property(models.Model):
......
def free_places():
places = 0
for r in self.rooms:
x = r.beds - ((r.tenant).size())
places = places + x
return places
class Profile(model.Models):
room = models.ForeignKey(Room, blank=True, null=True, related_name='tenant')
First of all I would like to know if free_places method should be: free_places(self) or free_places(). I think it has some errors too but I don't know how to test it, so here it's the question how can I call the method? and is it correct the function?
I want to call it from a django template.
To try it from "./manage.py shell" what do I need?
Thanks
It should be free_places(self):
You can define the method as a property and then call that from the template:
https://docs.djangoproject.com/en/dev/topics/db/models/#model-methods
Last example in that code block
def _free_places(self):
places = 0
for r in self.rooms:
x = r.beds - ((r.tenant).size())
places = places + x
return places
free_places = property(_free_places)