Well it is look like simple question. but i am in the learning stage can`t figure out.
This is my model class
class Store(models.Model):
file = models.FileField(upload_to=content_file_name)
file_name = models.CharField(max_length=100)
created_date = models.DateTimeField(auto_now_add=True)
userfild = models.ForeignKey(user,null=True, blank=True)
Ok for some clarification i just included my content_file_name function here
def content_file_name(instance, filename):
return os.path.join(
"user_%d" % instance.created_date, filename)
but the output of the folder structure looks like this
`None`
----filename
i can get the file_name instance like this --> intance.file_name
but when i enter instance.created_date it is return 'None' value.
What i am missing.? And my another doubt is i set it DateTimeField as auto_now_add=True So it`s saved into the db when form is submitted. But why None return?
auto_now_add is not populated until the object is saved. If you want a default that is applied as soon as the object is instantiated, use the default parameter with a callable:
created_date = models.DateTimeField(default=datetime.datetime.now)
Not quite sure that this is what you're asking, but here goes anyway:
You create an instance of any class by instantiating it:
Store()
In Python, this calls the class's init() function. Since you don't have one, it will use the 'constructor' from the class you're inheriting from, models.Model.
So, for example, you could do something like this:
my_store = Store()
my_store.file_name = 'some new name!'
Related
I am learning Django. I wrote a simple model and some views method in Django rest framework so that I can modify some particular attributes when needed to all the records that need that. Here is the model:
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=255)
isActive = models.BooleanField(default=True)
def __str__(self):
return self.name
Then, I created this view to modify the isActive session when I call it:
class CategoriesChangeActiveView(views.APIView):
def post(self, request, format=None):
try:
categories = request.data.get('categories')
for category in categories:
category = Category.objects.get(id=category['id'])
category.isActive = category['isActive']
category.save()
except Exception as e:
return Response({'error': 'Bad request'}, status=status.HTTP_400_BAD_REQUEST)
return Response({'success': 'Active changed'}, status=status.HTTP_200_OK)
Even when the format of my request is correct ( I debugged each line ) when it comes to the line category.isActive = category['isActive']it throws the error that'Category' object is not subscriptable`. I don't know why or how to fix it.
I saw in the official documentation, on older StackOverflow questions that this is doable, but I don't understand why I can't.
Can someone please suggest what I am doing wrong? Thank you
it's a simple mistake.
Simply change it as follows and it should be fixed:
categories = request.data.get('categories')
for category in categories:
category_obj = Category.objects.get(id=category['id'])
category_obj.isActive = category['isActive']
category_obj.save()
What you're doing is changing what the variable category is. You for loop and the unpacked variable is category, but then you get the model object and set the variable as category
So initially, the category variable is in fact a dictionary object, but you change it to be a django model object instance.
Specifically, the issue is here:
category = Category.objects.get(id=category['id'])
category.isActive = category['isActive']
You set category to be an instance of the Category model (which in this case corresponds to a db record, but that bit is a little irrelevant).
Accessing attributes on a class instance is not done by the square bracket notation, but rather dot notation.
So instead of category['isActive'] use category.isActive
If category was a dictionary, eg.
category = {
"name": "cat",
"isActive": True,
}
Then you would use the square bracket notation as category["isActive"] to get that value.
As it is, it's not a dict, so python thinks you are trying to subscript the instance somehow, which will not work.
I read the following code for customizing Document model.
class DocumentQuerySet(models.QuerySet):
def pdfs(self):
return self.filter(file_type='pdf')
def smaller_than(self, size):
return self.filter(size__lt=size)
class DocumentManager(models.Manager):
def get_queryset(self):
return DocumentQuerySet(self.model, using=self._db) # Important!
def pdfs(self):
return self.get_queryset().pdfs()
def smaller_than(self, size):
return self.get_queryset().smaller_than(size)
class Document(models.Model):
name = models.CharField(max_length=30)
size = models.PositiveIntegerField(default=0)
file_type = models.CharField(max_length=10, blank=True)
objects = DocumentManager() #overriding the default model manager
Now suppose i want to retreive files of type pdf and size less than 1000.
Then i need to do the following:
Document.objects.pdfs().smaller_than(1000)
But what's the use of doing this even when i could have simply obtained the desired result by filtering the default model manager 'objects' using the following command:
Document.objects.filter(file_type='pdf', size__lt=1000)
What is the difference in the execution of above two commands?
Manager and Queryset methods are defined and used in order to use repeatable code.
If your use case only happens once, perhaps you are better off being explicit in your query, however if you repeat the exact same code elsewhere, perhaps you are better off making it a manager/queryset method.
I am trying to build a single course platorm where I will only hold lessons units materials where only people with membership will be able to see it , however when I try to do retrieve Lesson.course_allowed_mem_types.all() I got the following error 'ManyToManyDescriptor' object has no attribute 'all' , how can I fix this simple error?
class Lesson(models.Model):
content_title = models.CharField(max_length=120)
content_text = models.CharField(max_length=200)
thumbnail = models.ImageField(upload_to='static/xxx/xxx/xxx/xxx')
link = models.CharField(max_length=200, null=True)
allowed_memberships = models.ManyToManyField(Membership)
def __str__(self):
return self.content_title
views
def get_context_data(self, **kwargs):
context = super(bootCamp, self).get_context_data(**kwargs)
context['lessons'] = Lesson.objects.all()
user_membership = UserMembership.objects.filter(user=self.request.user).first()
user_membership_type = user_membership.membership.membership_type
course_allowed_mem_types = Lesson.allowed_memberships.all()
context['course_allowed_mem_types'] = course_allowed_mem_types
return context
You can query many-to-many related field only for model instance, not model class. It's not really clear what exactly is "all concrete allowed membership objects for a Lesson class" (Lesson.allowed_memberships.all()).
Is it "all membership objects related to any of existing lesson objects" or is it "all membership objects that can be related to a lesson object"?
Those are different queries, and Lesson.allowed_memberships.all() does not imply either, it's incorrect usage.
If you want the former, something like this could work
Membership.objects.filter(lesson__in=Lesson.objects.all())
(You already have this as context['lessons'] so use that instead, just showing the idea)
I think,
One lesson may have many memberships. so you are selecting all lessons with all memberships Lesson.allowed_memberships.all() .
Try selecting a single lesson then retrieve associated members
lesson = Lessons.objects.filter(pk=1)
course_allowed_mem_types = lesson.allowed_memberships.all()
If you want to create custom list like type, it is always a good idea to inherit from collections.abc.Iterable. It provides common operations required to work on such container types.
You can't just call .all() on any object/type, that type definition actually has to have all() method defined in class or parent class.
e.g.
class ListLike:
def __init__(self):
...
def all(self):
return some_iterator
I have a django model that I want to attach an extra piece of information to, depending on the environment the instance is in (which user is logged in). For this reason, I don't want to do it at the database level.
Is this okay to do? Or are there problems that I don't foresee?
in models.py
class FooOrBar(models.Model):
"""Type is 'foo' or 'bar'
"""
def __init__(self, type):
self.type = type
in views.py
class FooCheck(FooOrBar):
"""Never saved to the database
"""
def __init__(self, foo_or_bar):
self.__dict__ = foo_or_bar.__dict__.copy()
def check_type(self, external_type):
if external_type == 'foo':
self.is_foo = True
else:
self.is_foo = False
foos_or_bars = FooOrBar.objects.all()
foochecks = map(FooCheck, foos_or_bars)
for foocheck in foochecks:
foocheck.check_type('foo')
extra credit question: Is there a more efficient way of calling a method on multiple objects i.e. replacing the last forloop with something clever?
Okay, this does not work. Trying to delete a FooOrBar objects throws a complaint about
OperationalError at /
no such table: test_FooCheck
To get around this I'm just not going to inherit from FooOrBar, but if anyone has a suggestion on a better way to do it I'd be interested in hearing it
I had a similar issue, I did something like:
class Foo(models.Model):
# specific info goes here
class Bar(models.Model):
# specific info goes here
class FooBar(models.Model):
CLASS_TYPES = {
"foo":Foo,
"bar":Bar
}
type = models.CharField(choices=CLASS_TYPES)
id = models.IntegerField()
#field to identify FooBar
then you can get the object back using
object = FooBar.CLASS_TYPES[instance.type].objects.get(id=instance.id)
where instance is the FooBar instance
Here's a Django model class I wrote. This class gets a keyerror when I call get_object_or_404 from Django (I conceive that keyerror is raised due to no kwargs being passed to __init__ by the get function, arguments are all positional). Interestingly, it does not get an error when I call get_object_or_404 from console.
I wonder why, and if the below code is the correct way (ie, using init to populate the link field) to construct this class.
class Link(models.Model)
event_type = models.IntegerField(choices=EVENT_TYPES)
user = models.ForeignKey(User)
created_on = models.DateTimeField(auto_now_add = True)
link = models.CharField(max_length=30)
isActive = models.BooleanField(default=True)
def _generate_link(self):
prelink = str(self.user.id)+str(self.event_type)+str(self.created_on)
m = md5.new()
m.update(prelink)
return m.hexdigest()
def __init__(self, *args, **kwargs):
self.user = kwargs['user'].pop()
self.event_type = kwargs['event_type'].pop()
self.link = self._generate_link()
super(Link,self).__init__(*args,**kwargs)
self.user = kwargs['user'].pop()
self.event_type = kwargs['event_type'].pop()
You're trying to retrieve an entry from the dictionary, and then call its pop method. If you want to remove and return an object from a dictionary, call dict.pop():
self.user = kwargs.pop('user')
Of course, this will fail with a KeyError when "user" is not present in kwargs. You'll want to provide a default value to pop:
self.user = kwargs.pop('user', None)
This means "if "user" is in the dictionary, remove and return it. Otherwise, return None".
Regarding the other two lines:
self.link = self._generate_link()
super(Link,self).__init__(*args,**kwargs)
super().__init__() will set link to something, probably None. I would reverse the lines, to something like this:
super(Link,self).__init__(*args,**kwargs)
self.link = self._generate_link()
You might want to add a test before setting the link, to see if it already exists (if self.link is not None: ...). That way, links you pass into the constructor won't be overwritten.
There's no reason to write your own __init__ for Django model classes. I think you'll be a lot happier without it.
Almost anything you think you want to do in __init__ can be better done in save.
I don't think you need the __init__ here at all.
You are always calculating the value of link when the class is instantiated. This means you ignore whatever is stored in the database. Since this is the case, why bother with a model field at all? You would be better making link a property, with the getter using the code from _generate_link.
#property
def link(self):
....
wonder why, and if the below code is the correct way (ie, using __init__ to populate the link field) to construct this class.
I once got some problems when I tried to overload __init__
In the maillist i got this answer
It's best not to overload it with your own
__init__. A better option is to hook into the post_init signal with a
custom method and in that method do your process() and
make_thumbnail() calls.
In your case the post_init-signal should do the trick and implementing __init__ shouldn't be necessary at all.
You could write something like this:
class Link(models.Model)
event_type = models.IntegerField(choices=EVENT_TYPES)
user = models.ForeignKey(User)
created_on = models.DateTimeField(auto_now_add = True)
link = models.CharField(max_length=30)
isActive = models.BooleanField(default=True)
def create_link(self):
prelink = str(self.user.id)+str(self.event_type)+str(self.created_on)
m = md5.new()
m.update(prelink)
return m.hexdigest()
def post_link_init(sender, **kwargs):
kwargs['instance'].create_link()
post_init.connect(post_link_init, sender=Link)
>>> link = Link(event_type=1, user=aUser, created_on=datetime.now(), link='foo', isActive=True)
providing keyword unique for link = models.CharField(max_length=30, unique=True) could be helpful, too. If it is not provided, get_object_or_404 may won't work in case the same value in the link-field exists several times.
signals and unique in the django-docs