Django ForeignKey Required? - python

I have a three classes:
class Location(models.Model):
name = models.CharField(max_length = 200)
class Student(models.Model):
name = models.CharField(max_length = 200)
email = models.EmailField()
class Exam(models.Model):
place = models.ForeignKey(Location)
taker = models.ForeignKey(Student)
score = models.DecimalField(max_digits = 5, decimal_places = 2)
When I run this it complains that Student doesn't have a a ForeignKey to Exam. Why?

It sounds like your actual database is out of sync with your model. You'll want to either drop and recreate your database using manage.py syncdb (easiest, but you will lose the data unless you use something like fixtures to reload initial data) or use a migration tool like South to upgrade your existing database to reflect the new data model.

You can try this on the manage.py shell:
from bar import models
l=models.Location("here")
s=models.Student(name="fred",email="foo#bar.com")
e = models.Exam(place=l,taker=s,score=99.9)
which I can do with no errors... Looks good to me..

In the admin.py file I had inlines = [StudentsInline] setting. This tries to enforce adding multiple Students to one exam (thinking it's on the One side of a OneToMany relationship).

Related

How to correctly migrate custom UserModel in Django

I have custom user model from AbstractUser. And in the user model i have 1 field as foreignKey to other model. So i can't make migrations because i recieve error:
no such table: app_userrate
I tired to comment this foreignKey field but it is not soulution cause i want to auto deploy app.
class UserRate(models.Model):
name = models.CharField(max_length=30, blank=False)
max_active_events_cnt = models.PositiveIntegerField(default = 5)
max_people_contacts_cnt = models.PositiveIntegerField(default = 30)
def __str__(self):
return self.name
def default_rate():
obj, created = UserRate.objects.get_or_create(name="Basic")
return obj.id
class User(AbstractUser):
rate = models.ForeignKey(UserRate, on_delete=models.PROTECT, default=default_rate)
rate_until = models.DateField(null=True, blank=True)
I want to understand what should i change to make migrations correctly
This isn't really about the user model specifically, nor about foreign keys. It's about the default attribute, which you have set to call a function which itself does a database lookup. Obviously, at the time the migrations are run, the db item does not exist.
There is a solution, but it will take a few steps. You would need to remove the default attribute at first and create the migrations without it (you may need to set null=True). Then, add a second migration to define the "Basic" UserRate object. Finally, add the default back in and create a third migration.

Build a learning platform - link exercise to its lesson - onetoone field or foreign key?

I'm trying to build a small project - an e-learning project. I'm trying to bind some exercises to its lesson id.
I've read the django docs and I don't know if I should use a OneToOne field or a Foreign Key.
I've tried the idea with the foreign key, as I feel like this is the right answer.
lessons - models.py (Lectie = lesson)
from django.db import models
# Create your models here.
class Lectie(models.Model):
YTLink = models.CharField(max_length = 100)
PDFLink = models.CharField(max_length = 100)
exercises - models.py (intrebare = question, variante = options, variantaCorecta = the right answer)
from django.db import models
from django.contrib.postgres.fields import ArrayField
from lectii.models import Lectie
# Create your models here.
class Exercises(models.Model):
idLectie = models.ForeignKey(Lectie, on_delete=models.DO_NOTHING)
intrebare = models.CharField(max_length = 300)
variante = ArrayField(models.CharField(max_length=300), null=True)
variantaCorecta = models.IntegerField()
def __str__(self):
return self.intrebare
I'm getting this error:
You are trying to add a non-nullable field 'idLectie' to exercises without a default; we can't do that (the database needs something to populate existing rows).
I will only add these questions from the back-end, they will not be added by the user, and I get this answer. Django doesn't know what ID to bind the exercise to.
So how should my model look so I can bind the exercise to its lesson? Is it okay this way and just adding a blank=True, and changing the ID after that? Or should I switch to a one-to-one relationship? Thanks.
Thanks.
If a lesson has multiple lessons, then a ForeignKey is appropriate. A OneToOne field is just a ForeignKey with a unique=True constraint, meaning only one relationship between the two objects is allowed.
As for your error, you have two options:
1) Set a default=... attribute, which wouldn't make sense in this case since it doesn't seem there should be a "default" exercise for each lesson.
2) Set the ForeignKey to blank=True, null=True, then set each Lesson manually. You can always remove blank=True, null=True and then migrate again.
You need to provide a default value:
DEFAULT_ID = 1
idLectie = models.ForeignKey(Lectie, on_delete=models.DO_NOTHING, default=DEFAULT_ID)
Also make sure that there is a row in the table of Other.

Creating a migration when factoring out a new model out of an already existing one

I have some code like this:
class Item(models.Model):
something = models.ForeignKey('SomethingElse')
property1 = models.TextField()
city = models.TextField()
street = models.TextField()
country = models.TextField()
And I would like to shape it like this:
class Address(models.Model):
city = models.TextField()
street = models.TextField()
country = models.TextField()
class Item(models.Model):
something = models.ForeignKey('SomethingElse')
property1 = models.TextField()
address = models.ForeignKey('Address')
When trying to migrate the Project, Django asks me to create a default value. How could I specify one? Alternatively, how could I create a migration that creates addresses based on what we already have in the DB and then tie those to items?
Migrations only deal with the table structure, they can't move the data for you:
Django can’t automatically generate data migrations for you, as it does with schema migrations, but it’s not very hard to write them.
You should add the Address model before making this change, manually migrate your data, and then remove the redundant fields from Item model. You can use data migrations to include these changes in your migrations.

Django CharField with choices, auto add possible choices to database on syncdb or migrate?

I know there is a way to automatically add values to database on syncdb, which is Fixtures. But I was thinking maybe there's a way to detect the choices and automatically create those number of choices on database on syncdb or migrate.
The reason why I want this:
SERVICE_TYPES = (
("SALE", _("Sale")),
("RENT", _("Rent"))
)
class ServiceType(models.Model):
type_of_service = models.CharField(_("Type of service"), choices=SERVICE_TYPES, default=SERVICE_TYPES[0][0], max_length=20)
class Meta:
verbose_name = "Service Type"
verbose_name_plural = "Services Types"
def __str__(self):
pass
class Service(models.Model):
service_type = models.ForeignKey(ServiceType)
product_family = models.ManyToManyField(ProductFamily)
class Meta:
verbose_name = "Service"
verbose_name_plural = "Services"
def __str__(self):
pass
I would like that, on syncdb, the ServiceType automatically generates the two possible choices on database, so then I can add services with the Sale and Rent choices available.
You can create a data migration that loops through SERVICE_TYPES and makes sure that the table for ServiceType reflects that. You can see how you can do that here: https://docs.djangoproject.com/en/1.8/topics/migrations/#data-migrations
Are you sure you don't want to make type_of_service an attribute on Service directly? It makes the most sense if you aren't going to add extra attributes to ServiceType. If you are going to add extra attributes for different types of services, I'd rather create a different subclass for each type of service.
Yes, you can add this to the model:
SERVICE_TYPES = (
('sale', 'Sale'),
('rent', 'Rent')
)
service_type=models.CharField(max_length=50, null=False, blank=False, choices=SERVICE_TYPES)

How to get ForeignKey model field

In Django 1.8
class OtherModel(models.Model):
somefield = models.CharField(max_length=20)
class Orderform(models.Model):
sell_item_id = models.CharField(max_length=20)
class Selled(models.Model):
orderform = models.ForeignKey("Orderform")
sell_count = models.IntegerField()
something = OtherModel.objects.get(id=sell_item_id)
I need to use something like OtherModel.objects.get(id=sell_item_id).
How to get sell_item_id in class Selled(models.Model):?
You schema couldn't be presented in SQL.
Option #1:
class Orderform(models.Model):
sell_item_id = models.CharField(max_length=20)
othermodel = models.OneToOneField("OtherModel")
and get it
Selled.objects.get(pk=1).orderform.othermodel
Option #2:
class Selled(models.Model):
orderform = models.ForeignKey("Orderform")
sell_count = models.IntegerField()
def something(self):
return OtherModel.objects.get(id=self.sell_item_id)
and get
Selled.objects.get(pk=1).something()
But I think you should better think about you DB schema.
It looks like you have a couple of questions, for the first, to get the related
Selled.objects.filter(order_form__sell_item_id =id_to_get).select_related('order_form')
Notice the __ (double underscore) before sell_item_id. This is important because it says, selected Selleed by the sell_item_id of the OrderForm. and select_related makes sure that order form is brought back in the results with a single call to the db.
Now, if you want to do that for OtherModel, you will need to create a similar ForeignKey field in the OtherNodel and this will allow you to make the same query as above. Currently, you have no such relation.
class OtherModel(models.Model):
somefield = models.CharField(max_length=20)
orderform = models.ForeignKey("Orderform")
OtherModel.objects.filter(order_form__sell_item_id =id_to_get).select_related('order_form')
Don't forget to run:
python manage.py makemigration
python manage.py migrate
This should solve the issue.

Categories

Resources