Foreign Fields in Django - django

I am currently working on a Django project.
I am using Foreign Fields in one of the models.
class Purchase (models.Model):
user = models.ForeignKey(User, blank = True, null = True)
game = models.ForeignKey(Game)
...
And accessing these values in views like
p = Purchase.objects.filter(user=request.user,game=request.POST['gameid'])
In DB(i am using Postgres), the fields in Purchase Table are user_id and game_id
respectively for user and game.
I think its the Django default to suffix foreign fields with _id.
So i tried a bit in manage.py shell
and i came to know that i am getting same amount of results even if i use
p = Purchase.objects.filter(user_id=request.user,game_id=request.POST['gameid'])
So my doubt is that whether the field names defined in model and exact names of those fields in DB can be used interchangeably? Any further information or explanation would be appreciated.
Thanks

Django does this for foreign key fields. If you want to have the same name in the database then you can define column name using db_column:
user = models.ForeignKey(User, db_column='user')
P.S you can use both user_id and user to reference foreign key. This is absolutely fine. But i will suggest you to use model level names to avoid confusions.

Related

Django model foreignkey or charfield?

Django Model and Form that I want to make
Hello. I'm fairly new to Django and I have a hard time understanding which model field to use. I didn't post any code because my code is so messy right now and most of it still following "Django for Beginner" book by William S. Vincent.
I have an app consisting 2 models, Product model and Production model. Some fields on production model are linked to product model. Then from production model, I make a form for user input using ModelForm. (There's a link to an image to help understanding model and form relation.)
I have several questions regarding this matter.
If I set product_id on Production Model as ForeignKey to Product, what field should I use for product_name and material?
When I use CharField for both product_name and material, there are entry for both product_name and material on form and I don't want that. How to change it to readonly and have value updated based on product_id? (I'm not sure if this is related to Django form or not.)
Right now I'm using ModelForm to make Production form and then using FormView to render the form. Is it the right approach? What is the difference between this one and CreateView from model?
Thank you in advance for any comments and answers.
If you have a name and a material on the product model, you don't need those on the production model unless they relate to the production object. If I were you, I'd have a foreign key on Production to the product. It might look something like;
class Production(models.Model):
product = models.ForeignKey(
to=Product,
verbose_name=_("Product"),
on_delete=models.CASCADE
)
machine = models.CharField(
verbose_name=_("Machine No"),
max_length=255
)
date = models.DateTimeField(
verbose_name=_("Date"),
blank=True,
null=True
)
Then your form might be;
class ProductionForm(forms.ModelForm):
class Meta:
model = Production
fields = (
'product',
'machine',
'date',
)
I would recommend using the django admin to get your models as you want them before you start working with views. If you know the data is being stored in a way you need, then you can worry about building the frontend. The admin is around page 70 of that book you've got. You can also do readonly fields with that.

Including fields from a OneToOneField in Django Admin

I am attempting to add the fields from a OneToOneField into my admin view. Here is an example of how my models look.
class Customer(BaseUser):
name = CharField()
address = CharField()
secondary_information = OneToOneField("SecondaryCustomerInfo", on_delete=SET_NULL, null=True)
class SecondaryCustomerInfo(models.Model):
email = EmailField()
And I tried adding in the fields as an inline like this.
class SecondaryCustomerInfoInline(admin.StackedInline):
model = SecondaryCustomerInfo
class CustomerAdmin(admin.ModelAdmin):
inlines = [SecondaryCustomerInfoInline]
But I get the error
<class 'user.admin.SecondaryCustomerInfoInline'>: (admin.E202) 'user.SecondaryCustomerInfo' has no ForeignKey to 'user.Customer'.
I'm used to putting the OneToOneField on the secondary model but my coworker asked that I put it on the main Customer model since we will be accessing that information more often. I think switching things around is what is tripping me up. How would I include the fields from SecondaryCustomerInfo on the admin view for Customer?
The answer would be to use Django Reverse Admin
From its documentation:
Module that makes django admin handle OneToOneFields in a better way. A common use case for one-to-one relationships is to "embed" a model inside another one. For example, a Person may have multiple foreign keys pointing to an Address entity, one home address, one business address and so on. Django admin displays those relations using select boxes, letting the user choose which address entity to connect to a person. A more natural way to handle the relationship is using inlines. However, since the foreign key is placed on the owning entity, django admins standard inline classes can't be used.
class CustomerAdmin(ReverseModelAdmin):
inline_type = 'stacked'
inline_reverse = ['secondary_information']

Which database design is better for django follow/unfollow?

I've been looking for a good database design for a twitter like social network site in my django project and I found two possibilities:
This one down here
class Following(models.Model):
follower = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='following')
following = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='followers')
And this other one
class User(AbstractUser):
follows = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='followed_by')
pass
Are these the same? Is there any difference here? Which one should I choose? I'm kind of new to this so I can`t figure out which one is the best option. I find the first one easier to understand.
If I add this to my user model
following = models.ManyToManyField('self', related_name="followers")
and run (assuming auth is the app where your user model is, and replacing 000X by the number of the generated migration)
python manage.py makemigrations auth
python manage.py sqlmigrate auth 000X
this is what I get:
CREATE TABLE `auth_user_following` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`from_user_id` integer NOT NULL, `to_user_id` integer NOT NULL);
ALTER TABLE `auth_user_following` ADD CONSTRAINT `auth_user__from_user_id_b9318b74_fk_auth_`
FOREIGN KEY (`from_user_id`) REFERENCES `auth_user` (`id`);
ALTER TABLE `auth_user_following` ADD CONSTRAINT `auth_user__to_user_id_b51bc961_fk_auth_`
FOREIGN KEY (`to_user_id`) REFERENCES `auth_user` (`id`);
ALTER TABLE `auth_user_following` ADD CONSTRAINT `auth_user_foll_from_user_id_to_au_88cd5a29_uniq`
UNIQUE (`from_user_id`, `to_user_id`);
So it creates a table with an auto-generated id and two foreign key columns, just as it would do with the explicit relation-only model, i.e. on the database side, there is no structural difference.
For code readability, I would much prefer to keep the relation in the model and not define it in a different class. However, if you want to add additional data to the relation (e.g. date_started_following), you will need an explicit relation model. Then, you might still want to mention this many-to-many-relation in your user model and point to the explicit relation using the through argument:
However, sometimes you may need to associate data with the
relationship between two models.
[...]
Django allows you to specify the model that will
be used to govern the many-to-many relationship. You can then put
extra fields on the intermediate model. The intermediate model is
associated with the ManyToManyField using the through argument to
point to the model that will act as an intermediary.
One other reason for the first approach or an explicit through model is that it might facilitate some queries about the relationship, e.g. "find users who follow each other".
I would suggest both models code will work fine.
If you want to create custom user model with new fields then use below code format.
AbstractUser: Use existing fields in the user model
AbstractBaseUser:In case want to create your own user model from
scratch
class User(AbstractUser):
follows = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='followed_by')
pass
You want to segregate your app related changes then use below models code.
class Following(models.Model):
follower = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='following')
following = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='followers')

How to revert Django PostgreSQL database model's primary key to an AutoField whilst maintaining foreign key and many to many relationships

I currently have a Django powered in-production web app that contains multiple models, sitting on top of a Postgresql database (Google Cloud SQL)
During initial set-up, one of the models was set up as follows:
class ExampleModel(models.Model):
id = models.CharField(max_length=60, unique=True, primary_key=True)
new_id = models.CharField(max_length=60, unique=True, null=True, db_index=True)
name = models.CharField(max_length=300, db_index=True)
tags = models.ManyToManyField(Tag, blank=True)
The id field contains a unique ID like: AB123456789.
I have since realised this is a mistake and would like to revert the primary key field to a standard auto-incrementing autofield, and instead use the 'new_id' field to store the unique ID.
Please can someone provide guidance on how I can make this change and perform the necessary database migrations? There are a number of foreign key fields in other models that currently use the id field in the above model which will need changing. As you can see in the above, there is also a many to many field between this model and a tag model.
I tried removing the id field from my models.py file and migrating - it initially gave an error linked to null fields and default values so I set a dummy default value in the Terminal window and removed this in the migration file.
The database removed the id field successfully and generated a new Autonumber primary key field however none of the many to many or foreign key relationships were kept post migration. I have since rolled back to a prior version of the database.
Generally this will be your approach. Steps 1-4 can be merged into a single deployment. Steps 5-7 into another. Then 8-9 would be the final.
Create new auto field.
Create new FK nullable relationships on models
Update all code that creates related models to populate both FK's
Populate all the null FK fields via a script
Make the new FK fields not-nullable
Make old FK's nullable.
Remove old FK usages from code base
Migration to remove old ID field and FKs.
(optional) Rename auto field to be ID and potentially use Django's built-in field.

Django models: database design for user and follower

In Django model I am making a table 'followers', which has:
user's id. (this is followed by)
user's id (this is follower)
that's simple a user can follow other users.
How should I define the model in Django?
I tried this, but does not work:
user = models.ForeignKey('self')
follower_id = models.ForeignKey('self')
How should this be done?
thanks
The 'self' argument won't work unless you have a model called self.
Assuming that your assignment model is called Following, and you're using the built in User model then you can do:
class Following(models.Model):
target = models.ForeignKey('User', related_name='followers')
follower = models.ForeignKey('User', related_name='targets')
This will likely need some further uniqueness and validation logic.
Note the related_name attribute, see https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.ForeignKey.related_name. This means that for a given user object you can do user.targets.all() to get users they follow, and user.followers.all() to get users who follow them.
Note also that Django returns target model instances, not IDs, in the ORM. This means that even though the underlying table may be called follower_id, in the python code following.follower will return an actual User object.
Seeing as Following is actually the through table for the many-to-many relationship between Users. I would create a Profile model which extends the Django User model, and then declare the many-to-many relationship (using ManyToManyField).
from django.contrib.auth.models import User
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
following = models.ManyToManyField(User, related_name='followers')
Use the many to many field.
followers = models.ManyToManyField('self', symmetrical=False)