Django Saving ForeignKey as Character instead of Integer Field - django

I have two models.One of the models has a pk of unique identifying strings. Sometimes it would be something like 'TTL123' and sometimes '000010'. For some reason when I created the foreignkey fields is using integers and the item '000010' shows up as 10. I can't save 'TTL123'. Why has django created the table as integer instead of character field? How do I change it? I've been looking at documentation and can't find answer.
class Item(models.Model):
item_id = models.CharField(max_length=255, primary_key=True)
# ... other fields...
class ItemRestriction(models.Model):
item = models.ForeignKey(Item, related_name='item', on_delete=models.PROTECT, blank=True, null=True)
How can I make the ForeignKey use a character field instead of integer? Now when I try to access item__item_id I get nothing, because it's 000010 in Item table and 10 on ItemRestriction. I don't understand why it's doing this.

You can use the to_field.
class ItemRestriction(models.Model):
item = models.ForeignKey(Item, related_name='item', to_field='item_id', on_delete=models.PROTECT, blank=True, null=True)
see: https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.ForeignKey.to_field
If possible, you might want to consider using an AutoField or some sort of field that handles unique=True and auto increments on creation.

Related

How to get 2 different classes in 1 model field in django?

I am working in a project, where I have to merge/combine different classes into one field.
I want to do it that way, because I have two different classes ParkingArea1 and ParkingArea2 and I want to have the choice from the Admin and WebInterface, to select any of these two areas from a single drop-down list, and ideally store them in another's model field.
These are my models:
class ParkingArea1(models.Model):
zone_name = models.Charfield(max_length=255, unique=True)
# some more unique fields below
def __str__(self): return self.zone_name
class ParkingArea2(models.Model):
area_name = models.CharField(max_length=200, db_index=True, null=True, unique=True)
# some more unique fields below
def __str__(self): return self.area_name
class ChooseYourArea(models.Model):
area = # here I want a field, which should be able to hold any of the above classes
# some other stuff
How should I reform my models to achieve that?
NOTE: ParkingArea1 and ParkingArea2 are two actively used tables filled with data, so a change within these models wouldn't be optimal.
I researched a bit but couldn't find something to fit my case.
I understand that an abstract Base Class could be used for this case, but such a Base Class won't allow me to list all the areas that I want. Is there an obvious approach that I missed?
You can't if you want to use ForeignKeys. Both ParkingArea1 and ParkingArea2 have their own primary keys. Django won't know which table that foreign key belongs to. You need 2 fields.
There are ways around that but you need to ensure data consistency at the Django level, and the performance would be abysmal.
What I ended up doing, was to create another class ParkingAreas with two fields, where each field can hold either ParkingArea1 or ParkingArea2:
class ParkingAreas(models.Model):
area1 = models.OneToOneField(ParkingArea1, on_delete=models.SET_NULL, blank=True, null=True, default=None)
area2 = models.OneToOneField(ParkingArea2, on_delete=models.SET_NULL, blank=True, null=True, default=None)
def __str__(self):
if self.area1 is not None:
return self.area1.area1
else:
return self.area2.area2
class ChooseYourArea(models.Model):
area = models.ForeignKey(ParkingAreas, on_delete=models.SET_NULL, blank=True, null=True)
# some other stuff
Now I can get all parking areas in one place, even selectable with a drop-down menu, and store them in a ForeignKey field.
That way, when I need to access the areas, I can make some django queries and get what I need.

How to make a model parameter unique by a other parameter in Django?

I want my id field to be unique per each customer field. Just like the option unique_for_date from Django (https://docs.djangoproject.com/en/1.11/ref/models/fields/#unique) but in this case, not date but customer.
class Sample(NGObject):
id = models.CharField(max_length=128, null=True, blank=False)
customer = models.ForeignKey(Customer, related_name="blood_samples", on_delete=models.SET(get_default_customer))
I believe this should be done, before the save() method?
When a User writes the wrong ID (that already exists) I would also like to present the information in the Admin Form just like it would for normal unique error.
class Meta:
unique_together = ('sample_id', 'customer',)
This has done the trick :)

Django: Annotate with field from another table (one-to-many)

Good day.
I wish to annotate my model with information from a different table.
class CompetitionTeam(models.Model):
competition_id = models.ForeignKey('Competition', on_delete=models.CASCADE, to_field='id', db_column='competition_id')
team_id = models.ForeignKey('Team', on_delete=models.CASCADE, to_field='id', null=True, db_column='team_id')
...
class Team(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=30)
teamleader_id = models.ForeignKey('User', on_delete=models.CASCADE, to_field='id', db_column='teamleader_id')
...
class Competition(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=30)
...
Looping through my competitions, I wish to retrieve the list of competitionteam objects to be displayed with the relevant team's name. I tried:
CompetitionTeam.objects.filter(competition_id=_competition.id).filter(team_id__in=joined_team_ids).annotate(name=...)
-where instead of the ellipses I put Subquery expressions in. However, I'm unsure of how to match the team_id variable. eg.
*.anotate(name=Subquery(Team.objects.filter(id=competitionteam.team_id)).values('name'))
Related is the question: Django annotate field value from another model but I am unsure of how to implement that in this case. In that case, in place of mymodel_id, I used team_id but it only had parameters from the Team object, not my competition team object. I didn't really understand OuterRef but here is my attempt that failed:
CompetitionTeam.objects.filter(competition_id=_competition.id).filter(team_id__in=joined_team_ids).annotate(name=Subquery(Team.objects.get(id=OuterRef('team_id'))))
"Error: This queryset contains a reference to an outer query and may only be used in a subquery."
The solution for my question was:
CompetitionTeam.objects.filter(
competition_id=_competition.id,
team_id__in=joined_team_ids
).annotate(
name=Subquery(
Team.objects.filter(
id=OuterRef('team_id')
).values('name')
))
Thanks.

Getting all objects with equal M2M fields

I am looking for a way to filter for all objects of the same type that have the same querysets for a M2M field.
class Comment(models.Model):
user = models.ForeignKey(User, related_name='comment_user')
content = models.CharField(max_length=5000, null=True)
private_to = models.ManyToManyField(User, null=True, related_name='private_to')
Given a comment object, I want to retrieve all other comments who have an equal M2M field (i.e. if the private_to field returns User 1 and User 2 for the comment, it will find all the other comments that contain exactly both of those users in the private_to field.)
Is there a concise, built-in way to do this?
Try something from this post:
comment = Comment.objects.all()[0] # Or the comment you want to filter by.
private_to_ids = list(comment.private_to.all().values_list('id', flat=True))
comments = Comment.objects.filter(private_to__exact=private_to_ids)

Querying across database tables

I've got Django tables like the following (I've removed non-essential fields):
class Person(models.Model):
nameidx = models.IntegerField(primary_key=True)
name = models.CharField(max_length=300, verbose_name="Name")
class Owner(models.Model):
id = models.IntegerField(primary_key=True)
nameidx = models.IntegerField(null=True, blank=True) # is Person.nameidx
structidx = models.IntegerField() # is PlaceRef.structidx
class PlaceRef(models.Model):
id = models.IntegerField(primary_key=True)
structidx = models.IntegerField() # used for many things and not equivalent to placeidx
placeidx = models.IntegerField(null=True, blank=True) # is Place.placeidx
class Place(models.Model):
placeidx = models.IntegerField(primary_key=True)
county = models.CharField(max_length=36, null=True, blank=True)
name = models.CharField(max_length=300)
My question is as follows. If in my views.py file, I have a Person referenced by name and I want to find out all the Places they own as a QuerySet, what should I do?
I can get this far:
person = Person.objects.get(name=name)
owned_relations = Owner.objects.filter(nameidx=nameidx)
How do I get from here to Place? Should I use database methods?
I'm also not sure if I should be using ForeignKey for e.g. Owner.nameidx.
Thanks and apologies for this extremely basic question. I'm not sure how to learn the basics of database queries except by trying, failing, asking SO, trying again... :)
The whole point of foreign keys is for uses like yours. If you already know that Owner.nameidx refers to a Person, why not make it a foreign key (or a OneToOne field) to the Person table? Not only do you get the advantage of referential integrity - it makes it impossible to enter a value for nameidx that isn't a valid Person - the Django ORM will give you the ability to 'follow' the relationships easily:
owned_places = Place.objects.filter(placeref__owner__person=my_person)
will give you all the places owned by my_person.
Incidentally, you don't need to define the separate primary key fields - Django will do it for you, and make them autoincrement fields, which is almost always what you want.
If u could redesign.Then
In owner nameidx can be a foreign key to Person(nameidx)
Placeref(structidx) could be a foreign key to Owner(structidx) and
Place(placeidx) could be a foreign key Place ref(placeidx)
Then u could deduce the place value easily..