How do I get a value from a different model in django? - django

Im new to django and im trying to figure out how to set the value in a model = to a value in another model
from django.db import models
from django.contrib.auth.models import User
class Company(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
name = models.CharField(max_length=100, null=True, blank=True) # This is the value I want
_id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return self.name
class Product(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE, null=True)
companyName = # I want the name here
_id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return self.name
I've tried these but they dont work
companyName = Company.name
companyName = models.CharField(Company.name, max_length=100, null=True, blank=True)

Company.name will not work because Company is a class, a template for making many Company objects, each with it's own name, so which Company object, or instance, do you want?
You need to get the particular Company first, and then you can set the companyName of the Product, or, you can set it when you save the Product instance, assuming you have a Company instance in mind, since you set null=True, so obviously if company is False, then there is no companyName.
Assuming you have a Company instance already when you save the Product model you can do:
class Product(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE, null=True)
companyName = # I want the name here
_id = models.AutoField(primary_key=True, editable=False)
def save(self, *args, **kwargs):
if self.company:
self.companyName = self.company.name
super(Product, self).save(*args, **kwargs)
def __str__(self):
return self.name
But, the next question is why do you want to even have a field called companyName when you have access to the name field of the Company instance anyway. Try to get it by:
# Get the Product instance you want
product = Product.objects.get(...)
# Then you can get the associated `Company` name like this:
print(product.company.name)
Suggestion
Lately I've been seeing many questions with something like:
_id = models.AutoField(primary_key=True, editable=False)
Not sure why, since Django does that automatically.

Related

Django - ForeignKey Filter Choices

I'd like to filter the choices that a user can choose in my ForeignKey Field.
I basically have a ForeignKey for the subject of the Test and the actual topic of the Test. These topics come from a different model and are linked to a subject. Now I'd like to filter the choices to only include the topics that are linked to the currently selected subject. Is that possible and if so, how?
models.py
class Test(models.Model):
student = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True)
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, blank=True, null=True)
thema = models.ForeignKey(Thema, on_delete=models.CASCADE, blank=True, null=True)
school_class = models.ForeignKey(SchoolClass, on_delete=models.CASCADE, blank=True, null=True)
grade = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(6)], blank=True, null=True)
date = models.DateField(default=datetime.date.today)
def save(self, *args, **kwargs):
if not self.school_class and self.student:
self.school_class = self.student.klasse
return super().save(*args, **kwargs)
class Thema(models.Model):
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, blank=True, null=True)
thema = models.CharField(max_length=50)
class Subject(models.Model):
teacher = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True)
name = models.CharField(max_length=20)
The Problem if I use this:
# thema model #staticmethod
def return_thema(subject):
themen = Thema.objects.filter(subject=subject)
return {'thema': themen}
#test model
thema = models.ForeignKey(Thema, on_delete=models.CASCADE, blank=True, null=True,limit_choices_to=Thema.return_thema(subject))
Is that I get the Error:
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
Meaning I can't get the objects of the Thema Model while the models are loading
EDIT (for Swift):
That seemed to resolve the error when trying to makemigrations, but I now get this error, when visiting the admin portal to create a new Test:
File "/Users/di/Code/Schule/GymnasiumApp/venv/lib/python3.10/site-packages/django/db/models/sql/query.py", line 1404, in build_filter
arg, value = filter_expr
ValueError: too many values to unpack (expected 2)
I think what you are looking for ideally would be ForeignKey.limit_choices_to
Please see the docs:
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.limit_choices_to
You can limit the choices available at a model level, which is enforced throughout the django app, including forms automatically.
Edit because OP provided more information
Ok so I believe if you declare the thema field on the test model like so, it will solve the issue, and I will explain why after:
class Test(models.Model):
student = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True)
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, blank=True, null=True)
thema = models.ForeignKey(Thema, on_delete=models.CASCADE, blank=True, null=True, limit_choices_to=Q('thema_set__subject_set'))
school_class = models.ForeignKey(SchoolClass, on_delete=models.CASCADE, blank=True, null=True)
grade = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(6)], blank=True, null=True)
date = models.DateField(default=datetime.date.today)
def save(self, *args, **kwargs):
if not self.school_class and self.student:
self.school_class = self.student.klasse
return super().save(*args, **kwargs)
We are essentially telling Django to evaluate the relationship between the limited choices "lazily" I.e. when the form is loaded dynamically. Django forms will look at the limit_choices_to field argument and apply it to the available choices.
I'm not 100% about the relationship of your models so the Q(...) I added, might actually need to be Q('subject_set')
If you use django forms you can use the model choice field.
In your view you can set your queryset of this choicefield. Zo you can filter it.
fields['your model field'].queryset = yourmodel.objects.filter(your filter parameters)
I think there is also problem in save method also. Aren't you need to write the name of the model inside like
return super(<modelName>).save(*args, **kwargs)

How do i modify my create function in Django model manager

So i have this model:
class Token(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=False)
code = models.IntegerField(default=code)
date_created = models.DateTimeField(auto_now_add=True)
expiration_date = models.DateTimeField(null=False, blank=True)
as you can see I have an expiration_date field. The reason why I set it to (null=False, blank=True) is because I want it to fill itself based of the date_created field, and I'm trying to do that from the model manager create method
I have little to no experience in model manager outside of custom user model manager.
Here's my first failed attempt:
class TokenManager(models.Manager):
def create(self, user, code, date_created):
exp = date_created + datetime.timedelta(minutes=10)
token = self.model(user=user, code=code, date_created=date_created, expiration_date=exp)
token.save()
return token
basically my goal here is to get the value of date_created field, add the value by 10 minutes and set it as the expiration_date. can anyone help me with this?
There is no need to use a ModelManger here. You can just set the expiration_date based on the field date_created by overwriting the save method.
Edit:
It is not possible to use self.date_created datetime within the save method. However it is possible to use django.utils.timezone.now()which is also used by auto_now_add .
from django.utils import timezone
class Token(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=False)
code = models.IntegerField(default=code)
date_created = models.DateTimeField(auto_now_add=True)
expiration_date = models.DateTimeField(null=False, blank=True)
def save(self, *args, **kwargs):
# Set the expiration_date based on the value of auto_now_add
self.expiration_date = timezone.now() + datetime.timedelta(minutes=10)
super(Token, self).save(*args, **kwargs)

How to perform query in Django

I need to filter the a particular user's bar in whcih reservations were made. I am a beginner in Django and have tried some methods which unfortunately didn't work.
models.py
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=254, unique=True)
class Bar(models.Model):
user_id = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Tables(models.Model):
table_no = models.CharField(max_length=14, unique=False)
bar = models.ForeignKey(to=Bar, on_delete=models.CASCADE)
def __str__(self):
return self.table_no
class Reservation(models.Model):
first_name = models.CharField(max_length=200)
table = models.ForeignKey(Tables, on_delete=models.CASCADE)
def __str__(self):
return self.first_name
Note: I wan to filter the reservations made in a particular user's bar
I know you might be having a hard time and its one the things you go through when you are learning..
1.Can you change this first
from
class Bar(models.Model):
user_id = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
def __str__(self):
return self.name
To
class Bar(models.Model):
user_id = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50, null=True)
def __str__(self):
return self.name
2.On querying your data can you can try this since our user will already on the bar
user_bar = Bar.objects.filter("Here you specify what you wanna filter by")
Or
user_bar = Bar.objects.get(id=pk)
When I used this query filter. it worked perfectly.
reservations = Reservation.objects.filter(table__bar__user_id=request.user)
subject title: People can come to the restaurant and book a reservation filling a form which uses the Reservation model. Then the reservation is connected to a Table which is connected to a bar and the owner of the bar. Now I need to be able to filter the reservations made in each bar owner restaurant.

Django inline formset with manytomany fields

Ive spent a fair bit of time searching on this subject without finding some real up to date answers. I'm trying to create a form that creates a db entry. The basic idea is this:
Many events can have many people
So, the struggle here is that the user needs to create an event where the user can select all the people that attend. Each person that attends though, has certain things that also needs to be tracked per event. See the model below:
models.py
from django.db import models
from django.contrib.auth.models import User[]
class PersonRole(models.Model):
role = models.CharField(max_length=20, choices=ROLE_CHOICES, unique=True)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return self.role
class PersonClass(models.Model):
name = models.CharField(max_length=100, choices=CLASS_CHOICES, unique=True)
color = models.CharField(max_length=6, choices=COLOR_CHOICES, unique=True)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(max_length=100, unique=True)
personclass = models.ForeignKey(PersonClass, on_delete=models.CASCADE, blank=True, null=True)
personrole = models.ForeignKey(PersonRole, on_delete=models.CASCADE, blank=True, null=True)
value = models.IntegerField(default=0)
reliability = models.IntegerField(default=0)
last_item = models.DateField(auto_now=False, blank=True, null=True)
last_event_attended = models.DateField(auto_now=False, blank=True, null=True)
last_manager_attended = models.DateField(auto_now=False, blank=True, null=True)
item_received = models.BooleanField(default=False)
note = models.TextField(null=True, blank=True)
core_attendee = models.BooleanField(default=False)
enabled = models.BooleanField(default=True)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return self.name
class Location(models.Model):
name = models.CharField(max_length=100, unique=True)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return self.name
class Boss(models.Model):
name = models.CharField(max_length=100, unique=True)
location = models.ForeignKey(Location, on_delete=models.CASCADE)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return self.name
class Raid(models.Model):
date = models.DateTimeField(auto_now_add=True)
boss = models.ForeignKey(Boss, on_delete=models.CASCADE, null=True, blank=True)
success = models.BooleanField()
attendees = models.ManyToManyField(Person)
created_by = models.ForeignKey(User,
related_name="raids", blank=True, null=True,
on_delete=models.SET_NULL)
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return str(self.date)
I've started down the path of just trying to use the generic in-built create\update\delete views and ran into this:
ValueError: 'roster.Person' has no ForeignKey to 'roster.Raid'.
forms.py
class RaidGenericCreateModelForm(forms.ModelForm):
class Meta:
model = Person
exclude = ()
RaidPersonFormSet = inlineformset_factory(Raid, Person, fields=['name', 'personclass', 'personrole', 'item_received'], extra=1, can_delete=False)
views.py
class RaidCreate(CreateView):
model = Raid
template_name = 'roster/raid_create.html'
form_class = RaidGenericCreateModelForm
success_url = None
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
person_form = RaidPersonFormSet
return self.render_to_response(
self.get_context_data(form=form,
person_form=person_form
)
)
There are 9-year old posts that say you cannot use inlineformset_factory with many to many fields. So my question here is, what are my options? What is the best way to go about simply creating an Event (referred to as Raid in the model) and at the same time selecting the people from the roster (referred to as Person in the model) and changing the options those people have associated to them for that event?
As an example of what I am trying to accomplish here:
Event 1
-Person A (selected, item_received=True)
-Person B (selected, item_received=False)
-Person C (selected, item_received=False)
-Person D (not selected, item_received=False)
Event 2
-Person A (selected, item_received=False)
-Person B (not selected, item_received=False)
-Person C (selected, item_received=True)
-Person D (selected, item_received=False)
Where the list of persons is showing all persons and some of the persons fields from the Person model.
The alternate thing you can do is use DjangoRestFramework for this purpose.
Using rest you can first send persons data to frontend then in frontend you can create Event and add person details for each event,and in last post all that data using javascript.Try it,it will surely work.

How take modal as data type for field of another modal in Django?

Here I have Seller modal which contains the contact field. I created a new model name as Contact which has fields contact_number and address.
I can simply give a foreign key to the contact field of Seller model to Contact model.
But here I want to use the Contact model as a new data type for the contact field of Seller model.
class Contact(models.Model):
contact_number = PhoneNumberField(blank=False, null=False)
address = models.TextField(blank=False, null=False)
def __str__(self):
return "%s" % self.name
class Seller(models.Model):
company_name = models.CharField(max_length=300, blank=False, null=False)
company_profile = models.TextField(blank=False, null=False)
contact = Contact() #Here I want use Contact model as data type for the contact field
def __str__(self):
return "%s" % self.company_name
Is this possible?
If yes Can anyone please Guide me for that. I am New in Django, I only have basic knowledge of Django.
Here I am using PostgreSQL as a database.
what ever database your are using django will take care of that, follow the documentation for changes in settings if your are using different database instead of sqllite.
class Contact(models.Model):
contact_number = PhoneNumberField(blank=False, null=False)
address = models.TextField(blank=False, null=False)
def __str__(self):
return "%s" % self.name
class Seller(models.Model):
company_name = models.CharField(max_length=300, blank=False, null=False)
company_profile = models.TextField(blank=False, null=False)
contact = models.Foreignkey(Contact,on_delete=models.CASCADE)
def __str__(self):
return "%s" % self.company_name
once go through documentation of foreignkey and models for more info #https://docs.djangoproject.com/en/2.1/topics/db/examples/many_to_one/