Is it possible, to skip the validation when calling manage.py?
During development i have to reset my database from time to time an initialize data with "manage.py loaddata ...".
In one of my template views i have following code:
class CharterModalEmailOption(MessagesMixin, CharterMixin, TemplateView):
footer_template = Mailtemplate.objects.get(slug='signatur')
manage.py fails with the message "Mailtemplate matching query does not exist." That's right, because the table is empty at this stage and i want to add entries with loaddata. So as long as manage.py validates my views i cannot add the data. Looks like a dead end.
I can solve the problem by defining "footer_template" inside class functions and not at class level.
Does anybody have an idea?
Thank you,
Andreas
You shouldn't ever set a field directly to a queryset, and instead you should use a constructor.
Doing it directly will mean this is only ever done when the class is first referenced which may result in outdated information.
Simply just provide a constructor so this field is only initialized when you create an instance of the class
class CharterModalEmailOption(MessagesMixin, CharterMixin, TemplateView):
def __init__(self, *args, **kwargs):
self.footer_template = Mailtemplate.objects.get(slug='signatur')
Related
I am trying to write a very simple management function that checks the timestamps of instances of the "Data" model via a Cronjob and deletes the ones older than 14 days. My current function looks like this:
class Command(BaseCommand):
help = 'Delete data instances older than 14 days'
def add_argument(self):
pass
def handle(self, *args, **options):
time_threshold = datetime.now() - timedelta(days=14)
to_delete = Data.objects.filter(timestamp__lt=time_threshold)
for instance in to_delete:
instance.delete()
Something must be wrong with this command, as I get a complaint:
NotImplementedError: subclasses of BaseCommand must provide a handle() method
There is a handle method in the above - where is the problem?
I had this problem because I was calling super in the subclass. When you do that, you call the super class's handle function, which complains that it needs to be overridden. Ugh. Dumb.
I had the same problem - check your indenting. The def handle() must be a function declared in your command subclass. If it's outdented, you're going to get the error because -- in fact -- your handle() function doesn't exist at the right lexical level.
In my Django project I need to provide a view to get random object from a model using django-rest-framework. I had this ListAPIView:
class RandomObject(generics.ListAPIView):
queryset = MyModel.objects.all().order_by('?')[:1]
serializer_class = MyModelSerializer
...
It worked fine but order_by('?') takes a lot of time when launched on big database. So I decided to use usual Python random.
import random
def pick_random_object():
return random.randrange(1, MyModel.objects.all().count() + 1)
class RandomObject(generics.ListAPIView):
queryset = MyModel.objects.all().filter(id = pick_random_object())
...
I found out a strange thing when tried to use this. I launched Django development server and sent some GET requests, but I got absolutely the same object for all of the requests. When dev server restarted and another set of requests sent I'm getting another object, but still absolutely the same one for all of requests - even if random.seed() was used first of all. Meanwhile, when I tried to get a random object not via REST but via python manage.py shell I got random objects for every time I called pick_random_object().
So everything looks good when using shell and the behavior is strange when using REST, and I have no clue of what's wrong.
Everything was executed on Django development server (python manage.py runserver).
As #CarltonGibson noticed, queryset is an attribute of RandomObject class. Hence it cached and cannot be changed any later. So if you want to make some changeable queryset (like getting random objects at every request) in some APIView, you must override a get_queryset() method. So instead of
class RandomObject(generics.ListAPIView):
queryset = MyModel.objects.all().filter(id = pick_random_object())
...
you should write something like this:
class RandomObject(generics.ListAPIView):
#queryset = MyModel.objects.all().filter(id = pick_random_object())
def get_queryset(self):
return MyModel.objects.all().filter(id = pick_random_object())
Here pick_random_object() is a method to get random id from the model.
Since it's an attribute of the class, your queryset is getting evaluated and cached when the class is loaded, i.e. when you start the dev server.
I'd try pulling a list of primary keys, using values_list() — the flat=True example does exactly what you need. Ideally cache that. Pick a primary key at random and then use that to get() the actual object when you need it.
So, how would that go?
I'd define a method on the view. If you forget the caching, the implementation might go like this:
# Lets use this...
from random import choice
def random_MyModel(self):
"""Method of RandomObject to pick random MyModel"""
pks = MyModel.objects.values_list('pk', flat=True).order_by('id')
random_pk = choice(pks)
return MyModel.objects.get(pk=random_pk)
You might then want to cache the first look up here. The caching docs linked above explain how to do that. If you do cache the result look into the db.models signals to know when to invalidate — I guess you'd post_save, checking the created flag, and post_delete.
I hope that helps.
In my Django model I have two fields, name (a regular CharField) and slug, a custom field that generates the slug based on a field name passed in the field definition, in this case I use name for this.
First, the model only had the name field, with it's corresponding migrations and all. Then I needed to add the slug field, so following South conventions, I added the slug field with unique=False, create the schema migration, then created a data migration, set the unique=True and create another migration for this last change.
Since the value of the slug is generated on model save, in the forwards method of the data migration what I did was to iterate over the queryset returned by orm['myapp.MyModel'].objects.all() and calling the save() method on each instance.
But the value of the slug field is never generated. Under an IPython session I did the same thing, but referencing the model as from myapp.models import MyModel, and worked. Using some debug statements, printing the type of the model returned by South's orm dict shows the real class, it doesn't appear to be an fake model constructed on the fly by South.
The slug field creates it's value when the pre_save method. How to force it to be called during a data migration? I need to ensure the uniqueness of the value so when the index is applied in a later schema migration, the columns doesn't contains duplicate values.
Thanks!
BTW: The slug field class does define the south_field_triple so South plays nice with it.
EDIT: Please see my answer. But more like an answer, it feels more like a hack. Is there a better/right way to do this?
Generally you should explicitly replicate the code that generates the field's contents as closely as possible in the migration (A rare example of purposeful code duplication). The code in your approach, even if it worked, would call pre_save as defined at the time of executing the migration, which may have changed or even fail with the models state at the time the migration was created (It may depend on other fields not being present at an earlier time etc.).
So the correct approach in you example would be to use slugify() directly, as it is done in the SlugField's pre_save method:
from django.template.defaultfilters import slugify
class Migration(DataMigration):
def forwards(self, orm):
"Write your forwards methods here."
for myobj in orm['myapp.MyModel'].objects.all():
myobj.slug = slugify(myobj.otherfield)
myobj.save()
I solved this temporarily by obtaining the model field instance and calling it's pre_save directly:
class Migration(DataMigration):
def forwards(self, orm):
"Write your forwards methods here."
# Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..."
for myobj in orm['myapp.MyModel'].objects.all():
slug_field = myobj._meta.get_field_by_name('slug')[0]
myobj.slug = slug_field.pre_save(myobj, add=False)
myobj.save()
However it feels cumbersome to take this into account for custom fields...
When using Model class like this:
class MyModel(models.Model):
def __init__(self, *args, **kwargs):
self.myfield = models.Field()
super(MyModel, self).__init__(*args, **kwargs)
It doesn't take into consideration myfield(in the admin form, when saving the object... )
But if i declare like that:
class MyModel(models.Model):
myfield = models.Field()
It works just fine.
Why?
Edit
I think i have a good reason: I have an abstract class UploadItem that defines a field called file like this: self.file = models.FileField(upload_to=upload_to) As you can see, in each child class, i have to call parent init method with appropriate upload_to variable(say 'videos' for Video model). So i cannot do it the normal way.
Because the Django ORM code does some serious meta-magic during class definition (just browse the django/db code to see how magic). You are doing an end-run around that magic by creating fields on the fly in the __init__() function.
Is there a really good reason for not creating the class in the normal way? If not, then do it the normal way. If you do have a good reason then get ready to get into the really deep end of the pool -- both of Python and Django.
Setting a dynamic path for the upload_to attribute is absolutely not a good reason for wanting to muck around with model field declaration.
This is something that Django handles already - if you set upload_to to a callable, you can return the correct value dependent on the model instance. See the documentation.
class dbview(models.Model):
# field definitions omitted for brevity
class Meta:
db_table = 'read_only_view'
def main(request):
result = dbview.objects.all()
Caught an exception while rendering: (1054, "Unknown column 'read_only_view.id' in 'field list'")
There is no primary key I can see in the view. Is there a workaround?
Comment:
I have no control over the view I am accessing with Django. MySQL browser shows columns there but no primary key.
When you say 'I have no control over the view I am accessing with Django. MySQL browser shows columns there but no primary key.'
I assume you mean that this is a legacy table and you are not allowed to add or change columns?
If so and there really isn't a primary key (even a string or non-int column*) then the table hasn't been set up very well and performance might well stink.
It doesn't matter to you though. All you need is a column that is guaranteed to be unique for every row. Set that to be 'primary_key = True in your model and Django will be happy.
There is one other possibility that would be problemmatic. If there is no column that is guaranteed to be unique then the table might be using composite primary keys. That is - it is specifying that two columns taken together will provide a unique primary key. This is perfectly valid relational modelling but unfortunatly unsupported by Django. In that case you can't do much besides raw SQL unless you can get another column added.
I have this issue all the time. I have a view that I can't or don't want to change, but I want to have a page to display composite information (maybe in the admin section). I just override the save and raise a NotImplementedError:
def save(self, **kwargs):
raise NotImplementedError()
(although this is probably not needed in most cases, but it makes me feel a bit better)
I also set managed to False in the Meta class.
class Meta:
managed = False
Then I just pick any field and tag it as the primary key. It doesn't matter if it's really unique with you are just doing filters for displaying information on a page, etc.
Seems to work fine for me. Please commment if there are any problems with this technique that I'm overlooking.
If there really is no primary key in the view, then there is no workaround.
Django requires each model to have exactly one field primary_key=True.
There should have been an auto-generated id field when you ran syncdb (if there is no primary key defined in your model, then Django will insert an AutoField for you).
This error means that Django is asking your database for the id field, but none exists. Can you run django manage.py dbshell and then DESCRIBE read_only_view; and post the result? This will show all of the columns that are in the database.
Alternatively, can you include the model definition you excluded? (and confirm that you haven't altered the model definition since you ran syncdb?)
I know this post is over a decade old, but I ran into this recently and came to SO looking for a good answer. I had to come up with a solution that addresses the OP's original question, and, additionally, allows for us to add new objects to the model for unit testing purposes, which is a problem I still had with all of the provided solutions.
main.py
from django.db import models
def in_unit_test_mode():
"""some code to detect if you're running unit tests with a temp SQLite DB, like..."""
import sys
return "test" in sys.argv
"""You wouldn't want to actually implement it with the import inside here. We have a setting in our django.conf.settings that tests to see if we're running unit tests when the project starts."""
class AbstractReadOnlyModel(models.Model):
class Meta(object):
abstract = True
managed = in_unit_test_mode()
"""This is just to help you fail fast in case a new developer, or future you, doesn't realize this is a database view and not an actual table and tries to update it."""
def save(self, *args, **kwargs):
if not in_unit_test_mode():
raise NotImplementedError(
"This is a read only model. We shouldn't be writing "
"to the {0} table.".format(self.__class__.__name__)
)
else:
super(AbstractReadOnlyModel, self).save(*args, **kwargs)
class DbViewBaseModel(AbstractReadOnlyModel):
not_actually_unique_field = IntegerField(primary_key=True)
# the rest of your field definitions
class Meta:
db_table = 'read_only_view'
if in_unit_test_mode():
class DbView(DbViewBaseModel):
not_actually_unique_field = IntegerField()
"""This line removes the primary key property from the 'not_actually_unique_field' when running unit tests, so Django will create an AutoField named 'id' on the table it creates in the temp DB that it creates for running unit tests."""
else:
class DbView(DbViewBaseModel):
pass
class MainClass(object):
#staticmethod
def main_method(request):
return DbView.objects.all()
test.py
from django.test import TestCase
from main import DbView
from main import MainClass
class TestMain(TestCase):
#classmethod
def setUpTestData(cls):
cls.object_in_view = DbView.objects.create(
"""Enter fields here to create test data you expect to be returned from your method."""
)
def testMain(self):
objects_from_view = MainClass.main_method()
returned_ids = [object.id for object in objects_from_view]
self.assertIn(self.object_in_view.id, returned_ids)