How should I give ForeignKey to model? - python

How should I give ForeignKey to model?
Now models.py has User&Item table like
from django.db import models
# Create your models here.
class User(models.Model):
user_id = models.CharField(max_length=200)
name_id = models.CharField(max_length=200)
regist_date = models.DateTimeField(auto_now=True)
class Item(models.Model):
user_id = models.CharField(max_length=200)
name = models.CharField(max_length=200)
item_name = models.CharField(max_length=200)
price = models.CharField(max_length=200)
I wanna treat user_id&name_id as Foreing key.User table is parent table,and Item is child one.I think user_id&name_id in Item should have ForeignKey like
class Item(models.Model):
user_id = models.ForeignKey()
name = models.ForeignKey()
However,how should I connect these 2 model is User is parent&Item is child ?How should I write it?

For sure, you have to read that.
Looks like One User -> Many Items.
Its ForeignKey and we have to set it in User model.
class Item(models.Model):
...
class User(models.Model):
...
item = models.ForeignKey(Item)

You can use something like
class Item(models.Model):
user = models.ForeignKey(User, related_name='items')
Accessing user_id from item will be
item.user.user_id
Accessing all items from a user will be
user.items.all()

It's a good idea to read the documentation on the ForeignKey field.
As for your question, you can connect the Item model to the User model like this:
class Item(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
Again, it's a good idea to read the documentation and figure out what exactly you need, such as what to do when a User object is deleted (the on_delete part in my code).

Related

Django: Filter records based on one to many relationship

I have following models,
class User(models.Model):
name = models.CharField(max_length=255)
...
class InsuranceProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
...
class ProductExpertiseMaster(models.Model):
class Meta:
db_table = 'product_expertise_master'
name = models.CharField(max_length=255)
main_category = models.CharField(max_length=255)
class UserProductExpertise(models.Model):
user = models.ForeignKey(User, on_delete=models.DO_NOTHING)
product_expertise = models.ForeignKey(ProductExpertiseMaster, on_delete=models.DO_NOTHING)
So what I am trying to do is I want to filter records based on various fields some of the belong to User model & some of them belong to the InsuranceProfile model.I am filter the records based on User & InsuranceProfile model which is working fine. Now i want to add one more filter which will be based on the UserProductExpertise model.I want to get all the InsuranceProfiles with User details who have some matching condition with product expertise entries in UserProductExpertise model. Any help would appreciated.
You can try like this using __isnull:
InsuranceProfile.objects.filter(user__userproductexpertise__isnull=False)
It will return all the users who has an entry in in UserProductExpertise model. For querying, you need to use all lowercase of the model name, (ie userproductexpertise) and add __isnull at the end of it.
I think you should make some changes in your models before proceeding further.
UserProductExpertise model is the bridge table between ProductExpertiseMaster and User, which provides a many-to-many relationship. If you won't add additional fields to UserProductExpertise model, you can drop it and define user relation in ProductExpertiseMaster model.
If you prefer using seperate model for this relationship, on_delete=models.DO_NOTHING is prone to errors, you can change it to models.CASCADE
Here is an example with many-to-many relation:
class User(models.Model):
name = models.CharField(max_length=255)
class InsuranceProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.CharField(("Content"), max_length=500)
class ProductExpertiseMaster(models.Model):
class Meta:
db_table = 'product_expertise_master'
name = models.CharField(max_length=255)
main_category = models.CharField(max_length=255)
user = models.ManyToManyField(User, verbose_name=("Users"), related_name="expertises")
For filtering your query:
InsuranceProfile.objects.filter(user__expertises__isnull=False)

Using a django model as a field for another model?

I have been tasked with creating Django Models for a hypothetical apartment booking application.
My question is: can I use a model that I've defined, as a field in another model?
For example, I will have one model called "Listing" that represents an apartment being listed.
class Listing(models.Model):
address = models.IntegerField()
owner = models.CharField(max_length=256)
duration = models.DurationField()
price= models.IntegerField()
I also want to have a "Booking" model that represents an apartment once someone has booked it. It will have the exact same info as a Listing, with the addition of the username of the person who booked it. So can I have my Booking model use Listing as a field? And then just have one extra field for the booker's username.
Any other tips/critiques are highly appreciated as I am a complete beginner at Django.
I'm not 100% sure what you mean by use Listing as a field
But to me, you should be looking at the different built-in model relationships that exist in Django.
In your particular case, you will probably want to use a One-to-One relationship like so,
class Listing(models.Model):
address = models.IntegerField()
owner = models.CharField(max_length=256)
duration = models.DurationField()
price= models.IntegerField()
class Booking(models.Model):
listing= models.OneToOneField(
Listing,
on_delete=models.CASCADE,
)
username = models.Charfield()
Now if a user can book more than one apartment at a time, you'll be interested in a ForeignKey relationship like so,
class Listing(models.Model):
address = models.IntegerField()
owner = models.CharField(max_length=256)
duration = models.DurationField()
price= models.IntegerField()
class Booking(models.Model):
listing= models.ForeignKey(
Listing,
on_delete=models.CASCADE,
)
username = models.Charfield()
Note that in both examples I used Charfield for the username, feel free to use whatever Django field you need.
The concept of a model as field is odd. What you can do is establish relationships between models, or to inherit one from the other. Given your situation, you can maybe inherit Booking from Listing:
The docs on this topic.
You'll have something like this:
class Listing(models.Model):
address = models.IntegerField()
owner = models.CharField(max_length=256)
duration = models.DurationField()
price= models.IntegerField()
class Booking(Listing):
#your new fields

Django admin - Inline with choices from database

I need some basic help with the django admin site. What I basically want to do is to be able to populate an inline with choices from the database. For example consider the following models:
class Item(models.Model):
description = models.CharField(max_length=100)
class Category(models.Model):
name = models.CharField(max_length=100)
item = models.ForeignKey(Item, on_delete=models.CASCADE, null=True, blank=True)
And in admin.py I have the following setup:
class CategoryAdminForm(forms.ModelForm):
name = forms.ChoiceField(choices = category_service.get_all_categories())
class CategoryInline(admin.TabularInline):
model = Category
form = CategoryAdminForm
class ItemAdmin(admin.ModelAdmin):
inlines = [CategoryInline]
admin.site.register(Item, ItemAdmin)
admin.site.register(Category)
What I want to be able to do is to insert categories into db, and when I want to insert an item, the categories inline to be populated with categories from the db.
With the current setup it is not working. It says that category is not an iterable object. What am I missing here?
You should replace your ChoiceField with a ModelChoiceField. They allow you to specify a queryset to populate the choices.
category = forms.ModelChoiceField(queryset=Category.objects.all(), empty_label="(Nothing)")

How to get all objects referenced as ForeignKey from given field in a module in django

I have two classes: Author and Book. I want class Authors to have an attribute that contains all books written by the said author, as referenced to as foreign key in the class Books. The method I did does not appear to be working, which I assume is because when the database is being created in migrations, no Books objects exist yet. Or so I believe, I'm pretty new at django.
class Author(models.Model):
AuthorName = models.CharField(max_length=255, unique=True)
books = Book.objects.get(pk=object_instance.pk)
class Book(models.Model):
BookName = models.CharField(max_length=255)
Author = models.ForeignKey('Author')
The error message I get is:
NameError: name 'Book' is not defined
Which I get, is because I'm referencing to another class without actually having and instance of that class. I just can't figure out a proper way to do this.
EDIT: I reformatted it to be like this:
class Author(models.Model):
AuthorName = models.CharField(max_length=255, unique=True)
books = author.book_set.all()
class Book(models.Model):
BookName = models.CharField(max_length=255)
Author = models.ForeignKey('Author')
which yields error:
NameError: name 'author' is not defined
Maybe I should just query for the datapoints I need later on in views as opposed to creating own field for them in models though..
EDIT 2: solution from answers:
So my mistake all along was to try to add the "books" field in the author table. I guess there's no way to do this then. I can get that method to work in views so I guess this is sort of solved, although not in the way I was originally planning to do it.
doing
class Author(models.Model):
AuthorName = models.CharField(max_length=255, unique=True)
class Book(models.Model):
BookName = models.CharField(max_length=255)
Author = models.ForeignKey('Author')
and then later doing this in views:
author = Author.objects.get(pk=1)
books = author.book_get.all()
yields the wanted result (which I sort of knew beforehand, but I was trying to implement a books field in the models, which, if i correctly understood, is not possible at least not with this method).
another solution:
class Author(models.Model):
AuthorName = models.CharField(max_length=255, unique=True)
class Book(models.Model):
BookName = models.CharField(max_length=255)
Author = models.ForeignKey(Author, related_name = "books")
You don't need to create a separate field in Authors model
class Author(models.Model):
AuthorName = models.CharField(max_length=255, unique=True)
class Book(models.Model):
BookName = models.CharField(max_length=255)
Author = models.ForeignKey('Author')
You can get all books of a particular author like:
author = Author.objects.get(id=1)
books = author.book_set.all()
Learn more about backward relationships here
Just add related_name to ForeignKey and you will be able to get all books made by an author.
For example:
class Book(models.Model):
...
author = models.ForeignKey('Author', related_name='books')
...
and later...
author = Author.objects.get(pk=1)
books = author.books.all()
You did something weird in line:
books = Book.objects.get(pk=object_instance.pk)
Just delete it. You will be able to use author.book_set. You can also use related_name parameter of ForeignKey.
See the Django docs: https://docs.djangoproject.com/en/4.0/ref/models/fields/#foreignkey

How to use UUID

I am trying to get unique IDs for my Django objects. In Django 1.8 they have the UUIDField. I am unsure how to use this field in order to generate unique IDs for each object in my model.
Here is what I have for the UUIDField
import uuid
from django.db import models
class MyUUIDModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
class Person(models.Model):
...
unique_id = MyUUIDModel()
I can reproduce the id for the UUID model, but everytime I do I get the exact same id. For Example:
person = Person.objects.get(some_field = some_thing)
id = person.unique_id.id
id then gives me the same id every time. What is wrong, how do I fix this?
I'm not sure why you've created a UUID model. You can add the uuid field directly to the Person model.
class Person(models.Model):
unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
Each person should then have a unique id. If you wanted the uuid to be the primary key, you would do:
class Person(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
Your current code hasn't added a field to the person. It has created a MyUUIDModel instance when you do MyUUIDModel(), and saved it as a class attribute. It doesn't make sense to do that, the MyUUIDModel will be created each time the models.py loads. If you really wanted to use the MyUUIDModel, you could use a ForeignKey. Then each person would link to a different MyUUIDModel instance.
class Person(models.Model):
...
unique_id = models.ForeignKey(MyUUIDModel, unique=True)
However, as I said earlier, the easiest approach is to add the UUID field directly to the person.
You need to use the class you created as a subclass when declaring your Person model like this:
import uuid
from django.db import models
class MyUUIDModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
class Person(MyUUIDModel):
...
This way Person becomes a subclass of MyUUIDModel and will inherit its id field definition.
EDIT: Actually I was wrong. It's not possible yet to implement it as DEFAULT_AUTO_FIELD as it has to inherit from IntegerField. Here's the ticket in the django project with feature request to make it possible. Once it's resolved I'll update my answer.
As of Django 3.2, if you want to use uuid as a pk for all your models on a project-wide level, you don't need a generic abstract model anymore. Just define DEFAULT_AUTO_FIELD setting
default value
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
so something like this should work
DEFAULT_AUTO_FIELD = 'django.db.models.UUIDField'
Or even better, create your own field.
DEFAULT_AUTO_FIELD = 'project.common.models.CustomUUIDField'
Where you also define uuid type etc.
As seen in the docs, it can also be applied on an app level.
class MyAppConfig(AppConfig):
default_auto_field = 'project.common.models.CustomUUIDField'
You can directly add the id field as a UUIDField in the Person model. There is no need for a separate MyUUIDModel.
I think you have confused it with the MyUUIDModel used in the UUIDField example where the id is a UUIDField. You can just use the below code and it will use UUIDs for id.
import uuid
from django.db import models
class Person(models.Model):
...
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
To use UUID in Django for a new model see Django Docs.
However, if you want to use it for the existing model (with unique=True) having data corresponding to it, you will not be able to do it directly by the above documentation. It will create migration errors.
To do it without losing the data follow all the steps carefully of this Django Documentation.
in model import uuid:
import uuid
in class model use:
class Article(TimeStampedModel):
uuid = models.UUIDField(editable=False, default=uuid.uuid4, unique=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='articles', null=True)
categories = models.ManyToManyField(ArticleCategory, blank=True)
title = models.CharField(max_length=500, null=True, blank=True)
body = RichTextUploadingField(config_name='portal_lobar_config')
image = models.ImageField(upload_to='article_images/', null=True, blank=True)
headline = models.BooleanField(default=True)
tags = models.ManyToManyField(ArticleTag, blank=True)
slug = AutoSlugField(max_length=500, populate_from='title', unique_with='created__month', null=True)
published = models.BooleanField(default=False)
published_at = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.title
class Meta:
ordering = ['-created']

Categories