I’m looking for a way to expand the list of relationship field arguments, e.g. to add a predicate for each direction of the relation. My first guess was to define a subclass of models.ForeignKey
class NewForeignKey(models.ForeignKey):
def __init__(self, parent, pred='', reverse_pred='', **kwargs):
self.pred = pred,
self.reverse_pred = reverse_pred
super(NewForeignKey, self).__init__(parent, **kwargs)
Then use this subclass in my models as in the following example:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = NewForeignKey (Question,
pred="refers to",
reverse_pred="includes",
on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
Initially, this seemed to work fine, however, when I tried to pass it through makemigrations it failed with the following error message:
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line 354, in execute_from_command_line
utility.execute()
File "C:\Python27\lib\site-packages\django\core\management\__init__.py", line 346, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\Python27\lib\site-packages\django\core\management\base.py", line 394, in run_from_argv
self.execute(*args, **cmd_options)
File "C:\Python27\lib\site-packages\django\core\management\base.py", line 445, in execute
output = self.handle(*args, **options)
File "C:\Python27\lib\site-packages\django\core\management\commands\makemigrations.py", line 99, in handle
ProjectState.from_apps(apps),
File "C:\Python27\lib\site-packages\django\db\migrations\state.py", line 178, in from_apps
model_state = ModelState.from_model(model)
File "C:\Python27\lib\site-packages\django\db\migrations\state.py", line 354, in from_model
e,
TypeError: Couldn't reconstruct field question on polls.Choice: __init__() takes at least 2 arguments (1 given)
To make things even simpler I tried from scratch to migrate as follows:
first without the FK,
then added the FK as models.ForeignKey and
finally replaced models.ForeignKey with NewForeignKey
Migrations after step (1) and (2) were successful (obviously). makemigrations after step (3) fails all the time with the same result whether I skip step (2) or not.
Digging deeper, I couldn’t find an explanation why this shouldn’t be possible. I understand that Django models have to be subclassed from django.db.models.Model (see here), but this isn’t the case with models.ForeignKey.
A clarification on this issue and/or any suggestions for a workaround or a clever alternative that would allow the use of additional relationship field arguments would be appreciated.
Related
im just stuck with error while making migrations to my django project.
in my project which is already 50% dveloped i use owner model to represent owner of shop and then i used user model for login and for registration purpose.
so i tried to use user model in my owner model so i could utilise both model effectively with additional fields.
i tried to extend user model in owner model using onetoone field.
after doing that i was not able to do migrations so i deleted all migrations files but after that it was start giving this error while doing migrations:-
py manage.py makemigrations
Traceback (most recent call last):
File "manage.py", line 21, in <module>
main()
File "manage.py", line 17, in main
execute_from_command_line(sys.argv)
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\core\management\__init__.py", line 401, in execute_from_command_line
utility.execute()
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\core\management\__init__.py", line 395, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\core\management\base.py", line 328, in run_from_argv
self.execute(*args, **cmd_options)
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\core\management\base.py", line 369, in execute
output = self.handle(*args, **options)
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\core\management\base.py", line 83, in wrapped
res = handle_func(*args, **kwargs)
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\core\management\commands\makemigrations.py", line 87, in handle
loader = MigrationLoader(None, ignore_no_migrations=True)
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\db\migrations\loader.py", line 49, in __init__
self.build_graph()
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\db\migrations\loader.py", line 274, in build_graph
raise exc
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\db\migrations\loader.py", line 248, in build_graph
self.graph.validate_consistency()
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\db\migrations\graph.py", line 195, in validate_consistency
[n.raise_error() for n in self.node_map.values() if isinstance(n, DummyNode)]
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\db\migrations\graph.py", line 195, in <listcomp>
[n.raise_error() for n in self.node_map.values() if isinstance(n, DummyNode)]
File "C:\Users\Mayur\PycharmProjects\StartUp\venv\lib\site-packages\django\db\migrations\graph.py", line 58, in raise_error
raise NodeNotFoundError(self.error_message, self.key, origin=self.origin)
django.db.migrations.exceptions.NodeNotFoundError: Migration listings.0001_initial dependencies reference nonexistent parent node ('owners', '0001_initial')
here is my Owner Model :-
from django.db import models
from django.contrib.auth.models import User
class Owner(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE, default=False)
name=models.CharField(max_length=200)
photo=models.ImageField(upload_to='photos/%Y/%m/%d/')
description=models.TextField(blank=True)
phone=models.CharField(max_length=20)
email=models.CharField(max_length=20)
def __str__(self):
return self.name
im hoping that will get help on this because i'm totally stuck here and also not getting how to tackle this problem.
You are using the term "migration folder of my django project" (in a comment above), and that is wrong -- each app in your project has its own migration folder. Specifically, there is still a migration in your "listings" app, and it lists as a dependency one of the migrations you deleted.
after reviewing and debugging that stack trace i finally get rid of that problem.
i delete the migration file 0001 from my listing app which was having relationship with Owner Model and then when i run makemigrations command it didn't given me any error or exception like i mentioned above.
I encountered a strange behavior while applying a signal to a new model, I'm not sure to understand what is wrong but it seems related with the fact that I used abstract classes.
The models (simplified)
Basically, I have Article, Photo (inheriting from Post)
class Post(models.Model):
class Meta:
abstract = True
some_field = models.Something()
class Article(Post):
category = models.ForeignKey(Article_category, null=True, on_delete=models.SET_NULL)
some_field = models.Something()
class Photo(Post):
category = models.ForeignKey(Photo_category, null=True, on_delete=models.SET_NULL)
some_field = models.Something()
and their respective Categories
class Category(models.Model):
class Meta:
abstract = True
parent = models.ForeignKey('self', null=True, blank=True, related_name='nested_category', on_delete=models.SET_NULL)
name = models.CharField(max_length=50)
count = models.PositiveSmallIntegerField(default=0, editable=False)
class Article_category(Category):
#classmethod
def load(cls):
cache.set('{}'.format(cls.__name__), cls.objects.all())
class Photo_category(Category):
#classmethod
def load(cls):
cache.set('{}'.format(cls.__name__), cls.objects.all())
The signal
A straighforward incremental counter. Every time an article/photo is created, it's corresponding category count is updated and the entire model is saved in the cache (for templating purposes)
from django.db.models import F
#receiver(post_save, sender=Article) ----> here comes trouble
#receiver(post_save, sender=Photo)
def add_one_to_count(sender, instance, **kwargs):
cat = type(instance.category).objects.get(name=instance.category)
cat.count = F('count')+1
cat.save()
cache.set('{}_category'.format(sender.__name__), type(instance.category).objects.all())
The problem
What you saw above works like a charm for #receiver(post_save, sender=Photo) but when I add #receiver(post_save, sender=Article), DB initialization with fixture fails and I only get emptyset tables (mariaDB). This very line is the only one changing fail to success and I can't figure why. Since count is defined in the abstract class, I wondered whether it had something to do with it, for I did not have any issue applying a similar logic to categories:
# this works perfectly
#receiver(post_save, sender=Photo_category)
#receiver(post_delete, sender=Photo_category)
#receiver(post_save, sender=Article_category)
#receiver(post_delete, sender=Article_category)
def refresh_cached_category(sender, instance, using, **kwargs):
cache.set('{}'.format(type(instance).__name__), type(instance).objects.all())
Thanks for any enlightenment
The complete Traceback
Traceback (most recent call last):
File "manage.py", line 21, in <module>
main()
File "manage.py", line 17, in main
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 375, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 323, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 364, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 72, in handle
self.loaddata(fixture_labels)
File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 114, in loaddata
self.load_label(fixture_label)
File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 181, in load_label
obj.save(using=self.using)
File "/usr/local/lib/python3.7/site-packages/django/core/serializers/base.py", line 223, in save
models.Model.save_base(self.object, using=using, raw=True, **kwargs)
File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 790, in save_base
update_fields=update_fields, raw=raw, using=using,
File "/usr/local/lib/python3.7/site-packages/django/dispatch/dispatcher.py", line 175, in send
for receiver in self._live_receivers(sender)
File "/usr/local/lib/python3.7/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
for receiver in self._live_receivers(sender)
File "/usr/src/cms/website/observers.py", line 26, in add_one_to_count
cat = type(instance.category).objects.get(name=instance.category)
File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 408, in get
self.model._meta.object_name
website.models.DoesNotExist: Problem installing fixture '/usr/src/cms/../test/data_dev.yaml': Article_category matching query does not exist.
You can't filter on name=instance.category in your query, because that's not a str. You need to filter on name=instance.category.name but first you also need to make sure instance.category isn't None (since it can be).
The thing I don't understand is why you perform a query in the first place, just to fetch the same object: instance.category is the same as ArticleCategory.objects.get(name=instance.category.name) assuming the name is unique, except you do an extra query to the db.
Also the query will raise an exception if you have two categories with the same name (which you don't exclude in your model). So your code should be:
def add_one_to_count(sender, instance, **kwargs):
if instance.category:
instance.category.count = F('count')+1
instance.category.save()
cache.set('{}_category'.format(sender.__name__), type(instance.category).objects.all())
I've been bashing my head on this problem for the past two hours or so and was wondering if someone could help me out. With this code:
ann = Announcement(**params)
ann.save()
# Push this announcement to each competitor's unread announcements queue
for competitor in Competitor.objects.all():
competitor.unread_announcements.add(ann)
#ann.competitor_set.add(competitor)
and the relevant model fields:
class Announcement(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=80, blank=False)
body = models.TextField(blank=False)
posted = models.DateTimeField(auto_now_add=True)
# ...
class Competitor(models.Model):
id = models.AutoField(primary_key=True)
unread_announcements = models.ManyToManyField('Announcement')
When we get to the line adding the announcement to the queue, we get this error:
Traceback (most recent call last):
File "./manage.py", line 16, in <module>
execute_from_command_line(sys.argv)
File "/usr/lib/python3.5/site-packages/django/core/management/__init__.py", line 350, in execute_from_command_line
utility.execute()
File "/usr/lib/python3.5/site-packages/django/core/management/__init__.py", line 342, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/lib/python3.5/site-packages/django/core/management/base.py", line 348, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/lib/python3.5/site-packages/django/core/management/base.py", line 399, in execute
output = self.handle(*args, **options)
File "/home/cam/Documents/Programming/web/pactf-web2/django/ctflex/management/commands/announce.py", line 40, in handle
ann.competitor_set.add(competitor)
File "/usr/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 843, in add
self._add_items(self.source_field_name, self.target_field_name, *objs)
File "/usr/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 963, in _add_items
(obj, self.instance._state.db, obj._state.db)
ValueError: Cannot add "<Competitor: <Competitor #1 'cam'>>": instance is on database "None", value is on database "default"
All my research on the topic has shown that this error is caused when one or both of the relevant objects hasn't been saved in the database. However, in this case, I'm literally saving the announcement two lines beforehand, and the competitor object already lives in the database. So, what am I doing wrong?
Try omitting the id field of your Models. Since you're noting using the default id filed Django provided.
I have 2 models Car and Offer. The car table is an existing table filled with vehicle specifications. In the django admin I want to map an offer to an existing car in the specs table. This means that when a click on an offer in admin, I want to be able to see a list with all cars - find the correct one - and save it on the offer. Ive done this by populating the foreignkey field with a list of choices based on the the existing car objects.
models.py:
class Car(models.Model):
brand = models.TextField(max_length=300, default= "")
model = models.TextField(max_length=300, default= "")
edition = models.TextField(max_length=300, default= "")
engineVolume = models.FloatField(default=0.0)
def __unicode__(self):
return smart_unicode(self.brand)
carIds = []
idx = 1
for car in Car.objects.all():
carIds.append((idx, car))
idx = idx + 1
class Offer(models.Model):
stringUrl = models.TextField(max_length=300)
extractionDate = models.DateTimeField(default=datetime.datetime.now, blank=True)
cars = models.ForeignKey(Car, default= "", choices=carIds, null=True, to_field='id')
this works perfectly. I click on an offer in admin and I see a selectionbox populated with all existing cars. I find the correct car, save it, and the offers´s foreignkey car id in the database points to the correct vehicle.
But suddenly when I want to make later migrations django says it cannot serialze the car object?
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python2.7/site- packages/django/core/management/__init__.py", line 338, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 330, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python2.7/site-packages/django/core/management/base.py", line 390, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python2.7/site-packages/django/core/management/base.py", line 441, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python2.7/site-packages/django/core/management/commands/makemigrations.py", line 143, in handle
self.write_migration_files(changes)
File "/usr/local/lib/python2.7/site-packages/django/core/management/commands/makemigrations.py", line 171, in write_migration_files
migration_string = writer.as_string()
File "/usr/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 166, in as_string
operation_string, operation_imports = OperationWriter(operation).serialize()
File "/usr/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 124, in serialize
_write(arg_name, arg_value)
File "/usr/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 87, in _write
arg_string, arg_imports = MigrationWriter.serialize(_arg_value)
File "/usr/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 377, in serialize
return cls.serialize_deconstructed(path, args, kwargs)
File "/usr/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 268, in serialize_deconstructed
arg_string, arg_imports = cls.serialize(arg)
File "/usr/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 303, in serialize
item_string, item_imports = cls.serialize(item)
File "/usr/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 303, in serialize
item_string, item_imports = cls.serialize(item)
File "/usr/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 465, in serialize
"topics/migrations/#migration-serializing" % (value, get_docs_version())
`enter code here`ValueError: Cannot serialize: <Car: Nissan>
There are some values Django cannot serialize into migration files.
For more, see https://docs.djangoproject.com/en/1.8/topics/migrations/#migration- serializing
I have no idea why this error occurs. I' m new to django and the just starting with the admin. I´ve been reading up on serialzation and deconstruction but cant see how to apply it here? Perhaps I should follow a different route to achieve what I want?
In my case I was tring to add a field like:
task = models.ForeignKey(Task, on_delete=models.CASCADE, default=Task.objects.first())
but corrected this by using:
task = models.ForeignKey(Task, on_delete=models.CASCADE, default=Task.objects.first().pk)
In a nutshell you don't need choices at all.
choices, although can be any iterable and can be modified, is more suited for static data.
Afterwards, this piece of code
carIds = []
idx = 1
for car in Car.objects.all():
carIds.append((idx, car))
idx = idx + 1
achieves nothing.
First, you are not filtering the choices in any way, just converting them to a list of tuples. Second, having a ForeignKey automatically provides choices from the referenced model's unfiltered queryset e.g. Car.objects.all().
So you could just drop choices, and if you need filtering in ModelForm and admin use ForeignKey.limit_choices_to instead.
Preface: I was writing my own Page app that used MPTT and a custom page model. This was working for me, but FlatPages is more refined than my custom Page Model and so I'm leaning toward just extending it.
from django.db import models
from django.contrib.flatpages.models import FlatPage
from mptt.models import MPTTModel
class ExtendedFlatPage(FlatPage, MPTTModel):
parent = models.ForeignKey('ExtendedFlatPage', null=True, blank=True, default=None, related_name="children", help_text="Hierarchical parent page (if any)")
class Meta:
ordering = ['flatpages__url']
order_with_respect_to = 'parent'
verbose_name = 'page'
verbose_name_plural = 'pages'
class MPTTMeta:
left_attr = 'mptt_left'
right_attr = 'mptt_right'
level_attr = 'mptt_level'
order_insertion_by = ['title']
def __unicode__(self):
return self.url
This almost works, except throws an error when I go to run python manage.py syncdb
Error:
iMac:cms colab$ python manage.py syncdb
Creating tables ...
Creating table my_flatpages_extendedflatpage
Traceback (most recent call last):
File "manage.py", line 14, in <module>
execute_manager(settings)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Django-1.3-py2.7.egg/django/core/management/__init__.py", line 438, in execute_manager
utility.execute()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Django-1.3-py2.7.egg/django/core/management/__init__.py", line 379, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Django-1.3-py2.7.egg/django/core/management/base.py", line 191, in run_from_argv
self.execute(*args, **options.__dict__)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Django-1.3-py2.7.egg/django/core/management/base.py", line 220, in execute
output = self.handle(*args, **options)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Django-1.3-py2.7.egg/django/core/management/base.py", line 351, in handle
return self.handle_noargs(**options)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Django-1.3-py2.7.egg/django/core/management/commands/syncdb.py", line 101, in handle_noargs
cursor.execute(statement)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Django-1.3-py2.7.egg/django/db/backends/util.py", line 34, in execute
return self.cursor.execute(sql, params)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Django-1.3-py2.7.egg/django/db/backends/mysql/base.py", line 86, in execute
return self.cursor.execute(query, args)
File "build/bdist.macosx-10.6-intel/egg/MySQLdb/cursors.py", line 174, in execute
File "build/bdist.macosx-10.6-intel/egg/MySQLdb/connections.py", line 36, in defaulterrorhandler
django.db.utils.DatabaseError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 2")
If anyone could point me in the right direction, I would greatly appreciate it. Thanks!
replace
class ExtendedFlatPage(FlatPage, MPTTModel):
with
class ExtendedFlatPage(MPTTModel, FlatPage):
This will allow MPTTModel class to override FlatPage attributes and methods.
#comment
It appears that something (an attribute, method) in FlatPage model overrides something in MPTTModel cousing this error.
order of classes you import from is important. here's an example:
class A:
attribute = 1
class B:
attribute = 2
class C(A,B):
pass
class C attribute value will be 1.