Not able to use foreign key from another app? - python

travelers.models
from django.db import models
class ShortInfoTraveler(models.Model):
name = models.CharField(max_length=200, blank=True)
email = models.EmailField(blank=True)
blogs.models
from django.db import models
from travelers.models import ShortInfoTraveler
class Title(models.Model):
shortinfotraveler = models.ForeignKey('ShortInfoTraveler')
title_text = models.CharField(max_length=255)
description = models.CharField(max_length=255, null=True, blank=True)
And When I run makemigrations, Terminal show following-
ERRORS: blogs.Title.shortinfotraveler: (fields.E300) Field defines a relation with
model 'blogs.ShortInfoTraveler', which is either not installed, or is abstract.

You should be setting your foreign key like this:
models.ForeignKey('travelers.ShortInfoTraveler')
If you want to use a string to set the foreign key relation.
Or you should just set ShortInfoTraveler without it being a string since you've imported it.
Setting it to "ShortInfoTraveler" is looking for the model in the current models file instead of your other app which you can see in the error message output back.

Related

It is impossible to add a non-nullable field 'id' to video without specifying a default

This is my models.py
from ast import Delete
from email.policy import default
from django.db import models
from django.contrib.auth.models import User
class Video(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title=models.CharField(max_length=100, null=False)
description=models.TextField(max_length=1000,null=True)
video=models.FileField(upload_to="video/%y",null=False)
def __str__(self):
return self.title
class Euser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = models.CharField(max_length=10,null=True)
birthdate = models.DateField(null=True,)
profile_pic = models.ImageField(null=True, )
cover_pic = models.ImageField( null=True, upload_to="images/%y")
def __str__(self):
return self.phone
when i try to makemigrations
It is impossible to add a non-nullable field 'id' to video without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
Provide a one-off default now (will be set on all existing rows with a null value for this column)
Quit and manually define a default value in models.py.
This error occurs...
Please suggest me what should i do
and also suggest me about any changes in model
For a particular model, in the database, if records already exist and add new fields to the model then it shows such an error. To overcome this problem, you have to set the new field as blank=True and null=True or you can set some default value to the new field using default='some_value'.

Why is Django giving me a ValueError when I reference a class within the same model?

I'm building a simple recipe app, and so far I have two models: Ingredient and Recipe.
Each recipe should have multiple ingredients, so I laid out my model like this:
class Ingredient(models.Model):
name = models.CharField(max_length=50)
class Recipe(models.Model):
title = models.CharField(max_length=100)
ingredients = models.ForeignKey(Ingredient, on_delete=CASCADE)
instructions = JSONField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=SET_DEFAULT, default='Chef Anon')
When I makemigrations, I get nothing, but when I migrate, I get this ValueError:
ValueError: Cannot alter field cookbook.Recipe.ingredients into cookbook.Recipe.ingredients - they do not properly define db_type (are you using a badly-written custom field?)
Following the example here (Django: Add foreign key in same model but different class), I've tried setting ingredients=models.ForeignKey(Ingredient, on_delete=CASCADE) as well as using lazy syntax ingredients=models.ForeignKey("Ingredient", on_delete=CASCADE), but each time, makemigrations shows no changes, and migrate gives me the same ValueError.
Edit
My imports:
from django.db.models.deletion import CASCADE, SET_DEFAULT, SET_NULL
from django.db.models.fields.json import JSONField
from django.utils import timezone
from django.contrib.auth.models import User```
Try replacing on_delete=CASCADE with on_delete=models.CASCADE
If you have not imported CASCADE separately from models.
All though, in that case you should get a warning that "CASCADE is not defined".
I believe I found the problem: My models.py file was in the root directory, not in the app directory.

ERRORS: book.Book.author: (fields.E300) book.Book.author: (fields.E307)

My English is poor, sorry
This is my struct:
bookstore
---author(app1)
---book(app2)
Or in code:
from django.db import models
from author.models import Profile
from django.contrib import admin
class Book(models.Model):
title = models.CharField(max_length = 150)
page = models.IntegerField()
price = models.IntegerField()
author = models.ForeignKey(
'Profile',
on_delete=models.CASCADE,)
publish_date = models.DateField()
class Meta(object):
db_table = "book"
class BookAdmin(admin.ModelAdmin):
pass
admin.site.register(Book, BookAdmin)
mysql have some data, now I want to use them to show my web, not to do that creat data in database. Thank you guys!
I have a question:
My Django == 1.9 , python == 3 , windows10
I want to use mysql (my database contect is really do it).
When I find some resource, I will see that
python manage.py sql [appname] it is Django to SQL
when I want to use Django to mysql.
Can I use python manage.py inspectdb? It will have a models.py
python manage.py sql [appname] = python manage.py inspectdb?
ERRORS:
book.Book.author: (fields.E300) Field defines a relation with model 'Profile', which is either not installed, or is abstract.
book.Book.author: (fields.E307) The field book.Book.author was declared with a lazy reference to 'book.profile', but app 'book' doesn't provide model 'profile'.
In your Book model, you refer with a field named author to a model Profile. Since that model is defined in another app, you should refer to it as app_name.ModelName, so likely that is:
class Book(models.Model):
title = models.CharField(max_length = 150)
page = models.IntegerField()
price = models.IntegerField()
author = models.ForeignKey(
'app1.Profile', # add name of the app
on_delete=models.CASCADE,
)
publish_date = models.DateField()
If you named this model Author however, as the question text (not the code), seems to suggest, you should use app1.Author. Of course you replace app1 with the real name of the app.
This is described in the documentation in the ForeignKey [Django-doc]:
To refer to models defined in another application, you can
explicitly specify a model with the full application label. For example, if the Manufacturer model above is defined in another
application called production, you’d need to use:
class Car(models.Model):
manufacturer = models.ForeignKey(
'production.Manufacturer',
on_delete=models.CASCADE,
)

Django MultipleObjectsReturned while using a legacy database

I am using Djano to develop a simple web app to display and manage database data. I hooked up a MySQL db and used inspectdb to auto generate a model based on the database tables and this is what I got back, which looks good.
# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
# * Rearrange models' order
# * Make sure each model has one field with primary_key=True
# * Make sure each ForeignKey has `on_delete` set to the desired behavior.
# * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
# Feel free to rename the models, but don't rename db_table values or field names.
from __future__ import unicode_literals
from django.core.exceptions import MultipleObjectsReturned
from django.db import models
class Booking(models.Model):
class Meta:
managed = False
db_table = 'Booking'
unique_together = (('hotelno', 'guestno', 'datefrom'),)
hotelno = models.OneToOneField('Hotel', models.DO_NOTHING, db_column='hotelNo', primary_key=True) # Field name made lowercase.
guestno = models.IntegerField(db_column='guestNo') # Field name made lowercase.
datefrom = models.DateTimeField(db_column='dateFrom') # Field name made lowercase.
dateto = models.DateTimeField(db_column='dateTo', blank=True, null=True) # Field name made lowercase.
roomno = models.OneToOneField('Room', models.DO_NOTHING, db_column='roomNo') # Field name made lowercase.
list_display =
#def __str__(self):
# return ("".join(hotelno) + "".join(guestno) + "".join(datefrom))
class Guest(models.Model):
guestno = models.AutoField(db_column='guestNo', primary_key=True) # Field name made lowercase.
guestname = models.CharField(db_column='guestName', max_length=255) # Field name made lowercase.
guestaddress = models.CharField(db_column='guestAddress', max_length=255, blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'Guest'
class Hotel(models.Model):
hotelno = models.AutoField(db_column='hotelNo', primary_key=True) # Field name made lowercase.
hotelname = models.CharField(db_column='hotelName', max_length=255, blank=True, null=True) # Field name made lowercase.
city = models.CharField(max_length=255, blank=True, null=True)
class Meta:
managed = False
db_table = 'Hotel'
class Room(models.Model):
roomno = models.IntegerField(db_column='roomNo', primary_key=True) # Field name made lowercase.
hotelno = models.ForeignKey(Hotel, models.DO_NOTHING, db_column='hotelNo') # Field name made lowercase.
type = models.CharField(max_length=255, blank=True, null=True)
price = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'Room'
unique_together = (('roomno', 'hotelno'),)
In the admin.py file for this app I included the models like so, so that I could at least see the data up there.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib import admin
# Register your models here.
from .models import Hotel, Room, Guest, Booking
admin.site.register(Hotel)
admin.site.register(Room)
admin.site.register(Guest)
admin.site.register(Booking)
When I access the default Django admin page, I'll see the tables registered on admin page.
I click on Bookings and see the multiple records, without names (for other reasons), but if I click on one of them I get the MultipleObjectsReturned Error
I've read everything I could find, and the closest thing to a reason I could find for why this is happening has to do with there being composite keys in some of the models. But, again, I don't know if that's the actual reason, I could also be missing something? I don't know.
I guess the reason is that data of Booking table not consistent with your model declaration. Django's admin detail view retrieves model by primary key.
You marked hotelno as PK:
hotelno = models.OneToOneField('Hotel', models.DO_NOTHING, db_column='hotelNo', primary_key=True)
Since some data already exists in Booking table, you have to make sure that hotelno values (hotelNo column) are unique or you will get MultipleObjectsReturned exception for non-unique pk values. Also make sure you've read this part of the documentation https://docs.djangoproject.com/en/1.11/ref/models/options/#managed
It looks like your booking table does not have a primary key and inspectdb guessed wrong when affecting it to the hotelno column of your booking table.
When the admin try to get the record by it's id it get multiple result since different booking can reference the same hotel multiple time.
What I would do on the booking model :
change hotelno and roomno to ForeignKey
remove the primary on hotelno
The new problem is now you have a model with no primary key. Django does not allow that. If you can alter the MySQL table add a primary key column to it and alter the booking model accordingly. If you can't alter the table I see no easy way to make it works.

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