I am reusing the News model from cmsplugin_news, just adding some extra fields in my inheriting model. (Multi-table inheritance, just as explained here.
from cmsplugin_news.models import News
class News(News):
departments = models.ManyToManyField('department.Department', blank=True, related_name="news")
On my admin.py I am extending NewsAdmin to set my own form:
class MyNewsAdmin(NewsAdmin):
form = NewsModelForm
Which I have defined in forms.py:
from news.models import News
class NewsModelForm(NewsForm):
class Meta:
model = News
widgets = {
'excerpt': CKEditorWidget(config_name='basic'),
'content': CKEditorWidget(config_name='default')
}
def _get_widget(self):
from ckeditor.widgets import CKEditorWidget
return CKEditorWidget()
The model inheritance seems to work well when I save objects from the shell console. But when I try to create a MyNews object from the django admin and link it to a department, this field is not saved. Or at least this change is not shown anywhere
unicms-testnews=> select * from cmsplugin_news_news;
id | title | slug | excerpt | content | is_published | pub_date | created | updated | link
----+-------+------+---------+---------+--------------+------------------------+-------------------------------+-------------------------------+------
1 | dfad | dfad | | | f | 2013-09-10 13:44:46+02 | 2013-09-10 13:45:04.709556+02 | 2013-09-10 13:57:05.568696+02 |
(1 row)
unicms-testnews=> select * from news_news;
news_ptr_id
-------------
1
(1 row)
unicms-testnews=> select * from news_news_departments;
id | news_id | department_id
----+---------+---------------
1 | 1 | 1
(1 row)
I can't understand anything, can anyone help me please? Thank you very much!
You created a form for News, that also exist in your DB since the model is not abstract, not for MyNews. Thus your current form has no field for the departments attribute, even if you add a widget with an input for it. Do the code bellow instead:
class MyNewsForm(NewsForm):
class Meta:
model = MyNews # instead of just News
...
What Django does in background is to create two relations: the cmsplugin_news_news stores all the News fields, and the news_news_departments stores your new field and is in one-to-one relation with the first relation.
Related
I'm new to django. I've been coding with sql but django orm is hard for me to convert my knowledge of sql to orm models.
I've client model
class client(models.Model):
c_id = models.AutoField(primary_key=True)
name= models.TextField()
age=models.IntegerField()
and address model
class address(models.Model):
c_id = models.ForeignKey(client, on_delete=models.CASCADE)
addr = models.CharField(max_lenght=20)
city= models.CharField(max_lenght=20)
This is my table
---------------------------
| c_id|Name | age |
---------------------------
| 1 | John | 23 |
----------------------------
| 2 | Rose | 20 |
----------------------------
------------------------------
| c_id|addr | city |
------------------------------
| 1 | buspark | florida|
------------------------------
| 2 | homesquare| florida|
------------------------------
how to get allclient with address in list
Look at values() docs
The values() method takes optional positional arguments, *fields,
which specify field names to which the SELECT should be limited. If
you specify the fields, each dictionary will contain only the field
keys/values for the fields you specify. If you don’t specify the
fields, each dictionary will contain a key and value for every field
in the database table.
__ allows get related data, so in your case it could look like this
address.objects.values('c_id__c_id', 'c_id__name', 'c_id__age', 'addr', 'city')
There are 2 models
class A(models.Model):
name = models.TextField()
class B(models.Model):
a = models.ForeignKey(A)
status = models.BooleanField(default=False)
Now I want to filter objects of class A based on the last data in class B status.
if there are 2 datas of Model B
id | a | status
1 | a | True
2 | abc | False
3 | a | False
4 | abc | True
So if I want to filter objects of Model A which are having status False.
In this case it will give me
a.
If I wanted to filter objects of Model A which are having status True.
In this case it should return me
abc.
I want to write a query something like
A.objects.filter(b__status__last=True)
Is it possible to do using filters?
I think you could use annotate effectively here.
A.objects.annotate(latest_b=Max("b__created_at")).filter(b__status=True).latest('latest_b')
Here, we're annotating each object of A to have a latest_by field and then fetching the latest object after filtering by the status of b. This should work properly.
Please try:
from django.db.models import Max, F
A.objects.annotate(latest=Max('b__id')).filter(b__id=F('latest'),b__status=True)
I am using the simple history library for my Django project. It's pretty nifty, but I'm having trouble showing aggregated history stats next to a base model object.
Here's what my model looks like:
from django.db import models
from django.contrib.auth.models import User
from simple_history.models import HistoricalRecords
class RepairForm(models.Model):
user_id = models.ForeignKey(User, on_delete=models.DO_NOTHING,)
return_number = models.CharField(max_length=200, unique=True)
status_id = models.ForeignKey(RFormStatus, on_delete=models.DO_NOTHING)
...
history = HistoricalRecords()
def __str__(self):
return self.return_number
The Docs lead me to believe the proper way of accessing historical records is using the history manager. I can get both sets of information I want:
All Forms (base model objects) -
RepairForm.objects.all()
User ID | Return Number | Status ID
-----------------------------------------------------------
33 | 0a6e6ef0-a444-4b63-bd93-ae55fe8a3cee | 65001
44 | 5f699795-5119-4dcd-8b94-34f7056e732c | 65002
...
A history calculation (history object)
In this example I am getting the latest event of each form -
RepairForm.history.all()\
.values('return_number').annotate(latest_event_date=Max('history_date'))\
.order_by('return_number')
Return Number | latest_event_date
-----------------------------------------------------------
0a6e6ef0-a444-4b63-bd93-ae55fe8a3cee | 7/27/2018
5f699795-5119-4dcd-8b94-34f7056e732c | 8/1/2018
...
I feel like this should be possible to do in one query though no? One query that outputs something like this:
User ID | Return Number | Status ID | latest_event_date
------------------------------------------------------------------------------
33 | 0a6e6ef0-a444-4b63-bd93-ae55fe8a3cee | 65001 | 7/27/2018
44 | 5f699795-5119-4dcd-8b94-34f7056e732c | 65002 | 8/1/2018
...
you can add a property for example "latest_event_date" that calculates the wanted result.then it is always calculated when you run a query on RepairForm!
#property
def latest_event_date(self):
....
I'm using django 1.10 and have the following two models
class Post(models.Model):
title = models.CharField(max_length=500)
text = models.TextField()
class UserPost(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
approved = models.BooleanField(default=False)
How do I get a list of all the posts including the 'approved' property for the logged in user if exists? So instead of multiple queries, it would be one left join query, pseudo-code:
select * from posts as p
left join user_posts as up
on up.post_id = p.post_id
and up.user_id = 2
Output
post_id | title | text | user_id | approved
1 | 'abc' | 'abc' | 2 | true
2 | 'xyz' | 'xyz' | null | null
3 | 'foo' | 'bar' | 2 | true
I created the models this way because the 'approved' property belongs to the user. Every user can approve/reject a post. The same post could be approved and rejected by other users. Should the models be setup differently?
Thanks
Update:
I'm trying to create a webpage to display all available posts and highlight the ones that the current user approved. I could just list all posts and then for each post check if the 'UserPost' table has a value, if yes get the approved property else ignore. But that means if I have 100 posts I'm making 100 + 1 calls to the db. Is it possible to do 1 call using ORM? If this is not possible, should the models be setup differently?
Then I think you need something like this:
Post.objects.all().annotate(
approved=models.Case(
models.When(userpost_set__user_id=2,
then=models.F('userpost__approved')),
default=models.Value(False),
output_field=models.BooleanField()
)
)
I am developing a hirerchical application where leaf nodes can be instances of different models. I can't figure out how to make it work with django-mptt app. Is this even possible in that application? If yes, what am I doing wrong? and if no, is there anything out there what does what I am trying to do?
The following is a basic structure of the models:
class FolderItemBase(MPTTModel):
order = models.PositiveIntegerField()
class Meta:
abstract = True
class MPTTMeta:
parent_attr = 'folder'
order_insertion_by = ['order']
class Folder(FolderItemBase):
folder = TreeForeignKey('Folder', related_name='folders', blank=True, null=True)
...
class Image(FolderItemBase):
folder = TreeForeignKey('Gallery', related_name='images') # cannot be null since leaf has to be inside of a folder
...
When I try to do the following I am only able to get the Folder children, and none of the images. Same thing when I try to get ancestors of the images
>>> folder1 = Folder.objects.create(title='Folder 1', order=0)
>>> folder2 = Folder(title='Folder 2', order=0)
>>> folder2.insert_at(folder1, save=True)
>>> image = Image(...)
>>> image.insert_at(folder1, save=True)
>>> folder1.get_children()
[<Folder: Folder 2>]
>>> image.get_ancestores()
[]
And this is how things are stored in the db after all of this:
Folder table
----------------
+----+-------+-----+------+---------+-------+-----------+----------+
| ID | order | lft | rght | tree_id | level | folder_id | title |
+----+-------+-----+------+---------+-------+-----------+----------+
| 1 | 0 | 1 | 4 | 1 | 0 | | Folder 1 |
+----+-------+-----+------+---------+-------+-----------+----------+
| 2 | 0 | 2 | 3 | 1 | 1 | 1 | Folder 2 |
+----+-------+-----+------+---------+-------+-----------+----------+
Images Table
------------
+----+-------+-----+------+---------+-------+-----------+
| ID | order | lft | rght | tree_id | level | folder_id |
+----+-------+-----+------+---------+-------+-----------+
| 1 | 1 | 2 | 3 | 1 | 1 | 1 |
+----+-------+-----+------+---------+-------+-----------+
As you can see it figures what should be the level number for the image and the correct (at at least it seems to be) left and right numbers however it does not update anything in the folder table so then when you try to do a query, nothing gets selected.
Any pointers are appreciated. Thank you.
AFAIK, this is not possible; django-mptt piggy backs on Django's QuerySet, which will only ever work with one type of things. You can a use the contenttypes framework to associate the "real" item with something like FolderItem, which would only be used for the hierarchy, e.g.
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class FolderItem(MPTTModel):
folder = TreeForeignKey('Folder', related_name='folders', blank=True, null=True
order = models.PositiveIntegerField()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class Meta:
abstract = True
class MPTTMeta:
parent_attr = 'folder'
order_insertion_by = ['order']
Then, when you're using the django-mptt manager methods and such, you'll get back a queryset of FolderItems, and you can access the Folder/Image for each as you iterate over the set, through the generic foreign key.
However, be aware that this will likely be costly in terms of database queries, since each time you access a generic foreign key, a new query must be issued.