Django cms - plugin manyToMany variable always empty - django

I wrote a simple plugin which display contact people, but I need to exclude some contact on certain pages. So I added a related model to my plugin which use an "structure_to_exclude" ManyToMany relationship. My issue, when I get this variable it's allways empty.
The cms_plugins.py
class VMContactContactPlugin(CMSPluginBase):
module = 'VM Contact Plugin'
render_template = 'vm_contact/calendars/contacts_list.html'
model = VMContactCalendarPluginModel
name = _('VM Contact plugin')
def render(self, context, instance, placeholder):
print 'Instance : {0}'.format(instance)
inst = instance.structure_to_exclude.all()
print 'Instance.all() result : {0}'.format(inst)
structures = Structure.objects.exclude(contact=None).exclude(pk__in=instance.structure_to_exclude.all().values_list('id',flat=True))
context.update({
'structures': structures,
})
return context
plugin_pool.register_plugin(VMContactContactPlugin)
The related model
class VMContactCalendarPluginModel(CMSPlugin):
structure_to_exclude = models.ManyToManyField(
Structure,
verbose_name=_(u'Structures à exclure'),
)
The Structure Models (Polymorphic !!)
class Structure(PolymorphicModel):
contact = models.ForeignKey(Contact, blank=True, null=True)
members = models.ManyToManyField(Contact, blank=True, null=True, related_name='%(class)s_members')
title = models.CharField(max_length=50, default='Castor')
description = models.CharField(max_length=254, blank=True)
categories = CategoryManyToManyField('aldryn_categories.Category',
verbose_name=_('categories'),
blank=True)
calendars = models.ManyToManyField(Calendar, blank=True)
has_pages = models.BooleanField(default=True)
avatar = FilerFileField(null=True, blank=True,
on_delete=models.SET_NULL)
classcss = models.CharField(max_length=1, choices=CSS_CLASS, default='5')
order = models.PositiveSmallIntegerField(default=0)
class Meta:
ordering = ['order']
Print results :
Instance : 93
Instance.all() result : []
Any idea ? I tried to retrieve the plugin instance with the ID (93) to be sure that was not an issue with instance var but it doesn't change anything...
Regards, robin

For every plugin you create, there's two versions once you publish.
The public and the draft versions. So its perfectly fine for the ids to change.
Because relationships vary from project to project, anytime your plugin has relationships, you need to explicitly tell the cms how to "copy over" these relationships when publishing the page.
Please adapt your plugin model to have the following method:
def copy_relations(self, oldinstance):
self.structure_to_exclude = oldinstance.structure_to_exclude.all()
You can read more about plugin relations in our docs.

Related

Merge Django models into a view

I am attempting to merge and pull data from three Django models into a view. Players and Events relate to each other in the Details model (a player can attend many events) using models.ForeignKey.
In other platforms I would have written a DB View to join tables and the application would query that view.
From what I understand Django does not support data views within Models.
Looking for help on how I would approach this in Django.
class Players(models.Model):
firstName = models.CharField(max_length=255)
lastName = models.CharField(max_length=255)
highSchool = models.CharField(max_length=255)
gradYear = models.IntegerField()
slug = models.SlugField(default="", null=False)
class Events(models.Model):
title = models.CharField(max_length=255)
location = models.CharField(max_length=255)
date = models.DateField()
class Details(models.Model):
event = models.ForeignKey(Events, on_delete=models.CASCADE)
player = models.ForeignKey(Players, on_delete=models.CASCADE)
height = models.IntegerField(default=None, blank=True)
weight = models.IntegerField(default=None, blank=True)
def playerdetail(request,slug):
playerinfo = Details.objects.get(id=1)
template = loader.get_template('playerdetail.html')
context = {
'playerinfo': playerinfo,
}
return HttpResponse(template.render(context, request))
You are actually doing what you needed to do with the code you provided.
When you are invoking a query on a model that connects those two entities (Players,Events), it performs the join when you try to access each of these properties through the foreign key fields.
For example, for accessing the player information (which makes the Django ORM perform the join operation in the background):
# Get the first name of the player
first_name = playerinfo.player.firstName
For filtering and showing in other places, you can use the notation field__subfield
For more information, please read the examples of this website:
https://books.agiliq.com/projects/django-orm-cookbook/en/latest/index.html

Fetching data from models using OneToOneField in Django

well my college is making us go learn a framework and make a website with it in a month, and it's really killing me, because of that I couldn't really get a good understanding of the Django framework as I am making progress while watching YouTube vids and reading docs.
Anyways my models are all messed up which made the job even harder, and whenever I solve a problem another one arises, but the deadline is close and making any changes to the models will cost me a great deal of time. This time my problem is about fetching data.
The concerned models are the following:
The User class for authentication
class User(AbstractBaseUser, PermissionsMixin):
id = models.AutoField(primary_key=True,null=False)
username = models.CharField(max_length=50)
email = models.EmailField(unique=True)
nom = models.CharField(max_length=255)
prenom = models.CharField(max_length=255)
usertype = models.CharField(choices=types,max_length=20,default="user")
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
is_superuser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
student_data = models.OneToOneField(Etudiant, on_delete=models.CASCADE,blank=True, null=True,related_name='Etudiant_access')
Prof_data = models.OneToOneField(Prof, on_delete=models.CASCADE,blank=True, null=True)
objects=UserManager()
def __str__(self):
return self.prenom + " " + self.nom
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
The Students(Etudiant) class for managing the students:
class Etudiant(models.Model):
filiere = models.ForeignKey(Filiere, on_delete=models.DO_NOTHING)
classe = models.ForeignKey(Classe,null=True, on_delete=models.DO_NOTHING)
notes = models.ManyToManyField(note,blank=True, null=True)
The class Classe (LMAO) for managing the different classes:
class Classe(models.Model):
#Cla_id = models.AutoField(primary_key=True, null=False)
Designation = models.CharField(max_length=100)
filiere = models.ForeignKey(Filiere, on_delete=models.CASCADE)
Epreuve = models.ManyToManyField(Epreuve,blank=True, null=True)
def __str__(self):
return self.Designation
The thing is that I wanna fetch all data of the Users that are students (which means that their Prof_data attribute is blank/null and their student_data attribute is pointing to the Etudiant(Student) class while having an Etudiant.classe attribute equals to a value in the view's parameters
I've solved a great deal of it but I'm stuck at the end
This is my view function:
#login_required
def class_info(request,design):
#getting the Classe(s) from the url which Designation == design
classe_now = Classe.objects.get(Designation=design)
print(classe_now) # This works like a charm
#getting the Students objects that are part of the class_now
Etudiants = Etudiant.objects.filter(classe=classe_now)
print(Etudiants) # This works too. It returns the 'Etudiant' objects from where i wanna access to the Users data
#getting the User data of the student objects (This is where i get confused)
students_to_show = User.objects.filter(student_data=Etudiants)
pprint(students_to_show)
return render(request, 'Prof/class_info.html')
I am really confused, you are truly my last hope in this, and thank you for your time.
You can filter your User model by selecting all users that do have empty/null relation to Prof model and nonempty/null relation to Etudiant model.
student_users = User.objects.filter(Prof_data__isnull=True, student_data__isnull=False)
then for each stident_user, you can fetch its student data in the following manner:
student_user = student_users[0]
student_user.student_data.filiere
student_user.student_data.classe
student_user.student_data.notes
You can then pass the queryset result to the render function as a context variable. Check this brief tutorial on how to pass data to templates.

Getting a column instead of an object when relating with PrimaryKeyRelatedField in Django-Rest-Framework

I have a model for applications, which among many attributes have a category. This category is in fact a key to another model that has the category ID, its name, and so on.
class Application(models.Model):
title = models.CharField(max_length=50)
vendor = models.CharField(max_length=50, default="Unknown", null=False)
.
.
.
category = models.ForeignKey('ApplicationCategory', related_name='applications', null=False, default=1, on_delete=models.SET_DEFAULT)
class ApplicationCategory(models.Model):
name = models.CharField(max_length=20, null=False)
description = models.CharField(max_length=200, null=False)
Then, on the Django REST serializers side I have the serializer for the applications:
class SoftwareSerializer(serializers.ModelSerializer):
category = serializers.PrimaryKeyRelatedField(queryset=ApplicationCategory.objects.all())
class Meta:
model = Application
fields = ['id', 'title', ... 'category']
Which is generating the expected API view, with a dropdown for the categories, but showing them as the ApplicationCategory objects and not giving me their name.
API showing Category dropdown with objects instead of names
Is there a way to access attributes of those objects to show the name in the dropdown, for usability sake?
I have also tried creating a CategorySerializer object (class CategorySerializer(serializers.ModelSerializer)) and then using it as category = CategorySerializer(many=False) but instead of dropdowns, I get open text fields for the attributes of the category.
Am I trying to do something that is not expected to work?
try to define the desired text in str method for your ApplicationCategory class:
class ApplicationCategory(models.Model):
name = models.CharField(max_length=20, null=False)
description = models.CharField(max_length=200, null=False)
#example
def __str__(self):
return '%s: %s' % (self.name , self.description)

Django: need help in designing relationships between models

I have an app which allows to associate to each client multiple boards, boards where I can upload files relevant for the client to make decisions about how the website page in question will look.
So the relationships I need to model are:
one client, multiple boards;
one board, one client;
one board, multiple files;
Let's concentrate on the first two
models.py
class Board(models.Model):
title = models.CharField(max_length=120, verbose_name="Titolo")
description = models.TextField()
files = models.FileField( null=True, blank=True, upload_to = 'clients_download_area', verbose_name = 'Client Reserved File')
date = models.DateTimeField(auto_now_add=True, verbose_name = 'Data di pubblicazione')
def __str__(self):
return str(self.title)
class Client(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=120)
boards = models.ManyToManyField(Board, blank=True)
def __str__(self):
return str(self.name)
Ok, relationship #1 is done. But what if I need to know which client is associated to a board (relationship #2)?
If I set a new field to Board Class
class Board(models.Model):
[...]
client = models.ForeignKey(Client, blank = True)
of course, when I makemigrations Django complains because it does not know what Client is, since I define it in the next model.
How can I design this DB?
Thank you in advance for any help you could provide
The problem here is that you reference to an identifer (here Client), before it is constructed (since Board is defined before the Client class).
Django has some support for this: you can pass strings that contain the name of the model. In the same app, you can just use ClassName, for another app, you can use other_app.ClassName, like the documentation says:
If you need to create a relationship on a model that has not yet been defined, you can use the name of the model, rather than the model
object itself:
from django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
'Manufacturer',
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
So here you can write it like:
class Board(models.Model):
title = models.CharField(max_length=120, verbose_name="Titolo")
description = models.TextField()
files = models.FileField( null=True, blank=True, upload_to = 'clients_download_area', verbose_name = 'Client Reserved File')
date = models.DateTimeField(auto_now_add=True, verbose_name = 'Data di pubblicazione')
client = models.ForeignKey(
'Client',
related_name='my_boards'
on_delete=models.CASCADE
)
def __str__(self):
return str(self.title)
class Client(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=120)
boards = models.ManyToManyField(Board, blank=True)
def __str__(self):
return str(self.name)
Note however that you already defined a ManyToManyField relation from Client to Board. Although it is possible it is not very common that two such relations exists simultaneously.
If you define a ForeignKey relationship from Board to Client, then Django automatically creates a reverse relationship (with the related_name), such that some_client.my_boards, is a manager of all the related Boards.
I think you can pass model class name instead of the class itself:
class Board(models.Model):
[...]
client_id = models.ForeignKey('Client', blank=True)

Django admin custom queryset for a custom action

I am a bit lost on how to perform a specific queryset in django admin. Below are my models.
class People(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=35)
phone_number = models.CharField(null=True, blank=True, max_length=15)
def __str__(self):
return self.first_name
class Meta:
verbose_name_plural = 'People'
class Group_and_message(models.Model):
name = models.CharField(max_length=30, null=True)
people = models.ManyToManyField(Person)
message_body = models.TextField(max_length=140)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
def __str__(self):
return self.name
In Admin, I have created a custom action.
def send_message(modeladmin, request,queryset):
pass
My question is to be able, when selecting a "group_and_message" object in the admin dashboard via the checkbox, be able to retrieve "id" and "phone_number" of the selected object so i can use it to perform "send_message" custom action.
Below is the equivalent of basic of a few queryset steps that showcase what i am trying to achieve(just for illustration purpose)
g = Group_and_message.objects.last() #self instead of last is what i want;
g1 = g.people.all()
g2 = g1.values_list("id","phone_number");
g3 = dict(g2)
The result gives me the "id" and "phone number".
Any help would be much appreciated.
You need to access the Group_and_message via the backwards relation. In this case for you, it should be group_and_message_set.
def send_message(modeladmin, request,queryset):
phone_map = dict(People.objects.filter(
group_and_message_set__in=queryset,
).distinct().values_list('id', 'phone_number'))
# Do something
class Group_and_messageAdmin(admin.ModelAdmin):
actions = ['send_message']
As an aside, you shouldn't have underscores in your model names. Rather than Group_and_message, it'd be more pythonic/django-like to use GroupMessage.