Django OneToOneField and ForeignKeyField add "_id" suffix to the field - python

When I checked group_cover table which is created by Django, there were group_id_id field and group_cover field.
I'd like to change group_id_id to group_id.
models.py
class Group(models.Model):
group_id = models.AutoField(primary_key=True)
group_name = models.CharField(max_length=50, unique=False, blank=False)
class Group_Cover(models.Model):
group_id = models.OneToOneField(Group, primary_key=True) # this create group_id_id
group_cover = models.ImageField(upload_to="/image/group/")
class Group_Member(models.Model):
user_id = models.ForeignKey(User2) # this create user_id_id
group_id = models.ForeignKey(Group) # this create group_id_id
Yeah, if I write,
group = models.OneToOneField(Group, primary_key=True)
It might work, but I may not need "_id" suffix on some field.
I read this document, but owing to my poor English, I couldn't understand the way.
Would you please teach me how to change?

Django adds an _id postix to primary keys that are generated automatically. You generally don't need to worry about them unless using a legacy data base.
Solution 2 would be the one i would recommend for a new project. Solution 1 for legacy databases.
Solution 1
To modify your existing code, use the following db_column attribute as it allows you to name the field in the database.:
group = models.AutoField(primary_key=True, db_column='group_id')
Documentation
Solution 2
To get the same results in a more "Django" way let Django generate the Primary keys automatically then reference the model in the OneToOne and Foreign key fields as shown below.
class Group(models.Model):
group_name = models.CharField(max_length=50, unique=False, blank=False)
class Group_Cover(models.Model):
group = models.OneToOneField(Group)
group_cover = models.ImageField(upload_to="/image/group/")
class Group_Member(models.Model):
user = models.ForeignKey(User2)
group = models.ForeignKey(Group)

Your assumption is correct, you need to rename your fields to not include the _id (i.e group instead of group_id). This will fix your "issue" but more than anything it more accurately represents the relationship/field. You have relationships to a model, not a reference to the id.
_id is an automatic reference provided by django to make it easier to just retrieve the _id from a model.
From the documentation
Behind the scenes, Django appends "_id" to the field name to create its database column name. In the above example, the database table for the Car model will have a manufacturer_id column. (You can change this explicitly by specifying db_column) However, your code should never have to deal with the database column name, unless you write custom SQL. You’ll always deal with the field names of your model object.

You should not worry about _id that is being added in database table. You should not deal with database if you are using ORM in Django. Also, you do not need to specify id unless its special type - group of attributes.
I would do it like this (I believe you do not need that many classes):
class Group(models.Model):
name = models.CharField(max_length=50, unique=False, blank=False)
cover = models.ImageField(upload_to="/image/group/")
users = models.ManyToManyField(User2)
Then you should access attributes with object notation. If you want id, use group.id, if you want to filter object, use Group.objects.filter(id__gt=10) or Group.objects.get(id=1) etc. My model should be doing exactly what you want to achieve.

Related

Fill DropDown list from data in database - Django

I would like to be able to add and remove items from LANGUAGES, instead of them being hardcoded like this. Now I get what I need, which is DropDown with 'English', 'German' and 'Italian' choice. Now i need them to be in a SQLite database and retrived from there, with option to add new languages and remove/edit existing. Thanks in advance...
LANGUAGES = [
("1", "English"),
("2", "German"),
("3", "Italian"),
]
language = models.CharField(max_length=50, choices=LANGUAGES, default=1, null=False)
You do that with a ForeignKey [Django-doc], For example:
class Language(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class MyModel(models.Model):
language = models.ForeignKey(Language, on_delete=models.PROTECT)
You can then populate the database with records for Language, and select the language for the MyModel objects.
If you use a ModelForm, then standard Django will make a dropdown with the options in the "target" model (and use str(…) to represent these objects).
It is probably better to set unique=True [Django-doc] for the name field, to prevent creating another Language object with the same name.
By setting on_delete=models.PROTECT we prevent removing a language, given MyModel refers with at least one object to that language. So you can only remove languages if no MyModel is referring to it anymore.
The database will normally guarantee referential integrity. That means that the language column stores the value of the primary key of the object it refers to. The database normally guarantees that if one such column contains a value x, then there is a primary key with that value in the table for Language.
If you're looking to do this in a form, create a new model for languages and populate the table.
class Language(Model):
name = models.CharField(max_length=50)
class MyLanguageForm(ModelForm):
language = forms.ModelChoiceField(queryset=Languages.objects.all())
# The rest

Django models queries

I have 3 tables person(id, email,password,type), user_location(id,location,u_id) and reviews(id,review,from_id,to_id). The user_location(u_id) is the foreignkey to person(id). The review(from_id,to_id) is also foreignkey to person(id). So how can i filter out a person with type 'a' and location 'b' and the reviews he got with the reviewers name?
models.py
class Person(models.Model):
email = models.CharField(max_length=30)
pwd = models.CharField(max_length=30)
type = models.CharField(max_length=30)
class User_locations(models.Model):
location = models.CharField(max_length=30)
u_id = models.ForeignKey('Person', on_delete=models.CASCADE)
Not sure if I really understand what you're trying to do but this should point you in the right direction. Don't forget to refer to the doc for Many-to-one relationships and Lookups that span relationships. It says there:
To refer to a “reverse” relationship, use the lowercase name of the model.
And then use the normal __ to access attributes.
a_and_b = Person.objects.filter(type='a', user_locations__location='b')
reviewers = Person.objects.filter(to_id__in=a_and_b)
The first query selects all users with type a and location b. The second query filters on those results. This is all untested so you might need to tweak a little. Bottom line: follow the relationships. As a side note, you might want to read up on Django model naming conventions.

Django Two Model Fields, same DB Column

We are trying to work with legacy DB Tables that were generated outside of Django and are not structured in an ideal way. We also can not modify the existing tables.
The DB uses the same user ID (pk) across all the tables, wether or not there is a record for that user ID. It also uses that ID as a PK on the other tables, rather than rely on them to auto increment their own IDs.
So imagine something like this below:
class Items(models.Model):
user_id = models.ForeignKey('User', db_column='UserID')
class User(models.Model):
user_id = models.IntegerField(primary_key=True)
class UserTypeA(models.Model):
user_id = models.IntegerField(primary_key=True) # Same Value as User
class UserTypeB(models.Model):
user_id = models.IntegerField(primary_key=True) # Same Value as User
What we thought of creating a relationship between Items and UserTypeA (as well as UserTypeB) is to create another field entry that uses the same column as the user_id.
class Items(models.Model):
user_id = models.ForeignKey('User', db_column='UserID')
user_type_a = models.ForeignKey('UserTypeA', db_column='UserID')
user_type_b = models.ForeignKey('UserTypeB', db_column='UserID')
This unfortunately returns a "db_column is already used" type error.
Any thoughts on how to better approach the way what we're trying to do?
A detail to note is that we're only ever reading from this databases (no updates to), so a read-only solution is fine.
Thanks,
-RB
I've solved a similar problem with this (this code should be put before the definition of your Model):
from django.db.models.signals import class_prepared
def remove_field(sender, **kwargs):
if sender.__name__ == "MyModel":
sender._meta.local_fields.remove(sender.myFKField.field)
class_prepared.connect(remove_field)
(Tested in Django 1.5.11)
Django uses local_fields to make the CREATE TABLE query.
So, I've just attached the signal class_prepared and check if sender equals the class I was expecting. If so, I've removed the field from that list.
After doing that, the CREATE TABLE query didn't include the field with same db_column and the error did not ocurr.
However the Model still working properly (with manager methods properly populating the removed field from local_fields), I can't tell the real impact of that.

Django point ForeignKey to an existing relationship table

I am reasonably new to Django and I want to achieve the following: I have a relationship between two tables, say table B has a ManyToMany reference to table A. Now I want a table called Options which saves options to a specific combination between A & B. How do I achieve this?
Thanks!
Hidde
Use the through option of the ManyToMany Field, and add the information in the relationship itself.
For example
class Ingredient(models.Model):
name = models.TextField()
class Recipe(models.Model):
name = models.TextField()
ingredients = models.ManyToManyField(Ingredient, through='RecipePart')
class RecipePart(models.Model)
recipe = models.ForeignKey(Recipe)
ingredient = models.ForeignKey(Ingredient)
amount = models.IntegerField()
# ...
RecipePart(recipe=pizza, ingredient=cheese, amount=9001).save()
If the relationship already exists (and you already have data) you will have to update the database schema (and create the model if you used to automatic mapping). South can help you do this.

queries in django

How to query Employee to get all the address related to the employee, Employee.Add.all() does not work..
class Employee():
Add = models.ManyToManyField(Address)
parent = models.ManyToManyField(Parent, blank=True, null=True)
class Address(models.Model):
address_emp = models.CharField(max_length=512)
description = models.TextField()
def __unicode__(self):
return self.name()
Employee.objects.get(pk=1).Add.all()
You need to show which employee do you mean. pk=1 is obviously an example (employee with primary key equal to 1).
BTW, there is a strong convention to use lowercase letters for field names. Employee.objects.get(pk=1).addresses.all() would look much better.
Employee.Add.all() does not work because you are trying to access a related field from the Model and this kind of queries require an instance of the model, like Ludwik's example. To access a model and its related foreign key field in the same query you have to do something like this:
Employee.objects.select_related('Add').all()
That would do the trick.
employee = Employee.objects.prefetch_related('Add')
[emp.Add.all() for emp in employee]
prefetch_related supports many relationships and caches the query set and reduces the database hits hence increases the performance..

Categories

Resources