Pycord embed make customizeable fields - python

I want to make customizable fields in python with pycord. by that i mean a command with a customizable amount of fields for each field i want to make a customizable value and name so that for each field the content can be different in the embed. so far i wrote that bit of code:
async def daily(ctx, *fields: discord.Option(int)):
d1 = today.strftime("%d/%m/%Y")
embed = discord.Embed(title=f"{d1}", description="", color=discord.Color.dark_purple())
for field in fields:
embed.set_footer(text="", icon_url="")
await ctx.respond(embed=embed)
but i don't really know what to do in the loop. by customizable i mean discord.Option also for the value and name for the fields. So for each field i want to enter a custom value and name through discord.Option
As i said i didnt do to much but i sat one it for atleast 3-4 hours and didnt came up with much.

To add parameters to a slash command, you need to do the following:
slash_command(ctx, parameter:discord.Option(int, "Name of parameter", required=False):
The first parameter of discord.Option is the type of the option. The next parameter is the name. Then you can set kwargs.
Automating this would be extremely difficult and ineffective. Even if you figured out how to automatically add parameters, you would have to constantly reload commands each time. This would be ineffective and wouldn’t be very scalable. An alternative to this would be adding as selector (with pycord’s built in discord.ui) to the message itself instead of as a command parameter.

Related

How to add dynamic arguments in slash commands [discord.py]

The Question
I'm trying to make a command that shows you the schedule of your class, for that, the user first introduces as an argument its degree and then the class, but every degree has a different number of classes, so I can't show a generic list for all the degrees.
The actual code:
class Ciclos(enum.Enum):
ASIX = 1
DAM = 2
class ASIX(enum.Enum):
_1A = 1
_1B = 2
_1C = 3
_2A = 4
_2B = 5
class DAM(enum.Enum):
_1A = 1
_2A = 2
_2B = 3
#bot.tree.command(name="schedule", description="Shows the schedule of the selected class")
#app_commands.describe(ciclo="Choose your degree")
#app_commands.describe(clase="Choose your class")
async def schedule(interaction: discord.Interaction, ciclo: Ciclos, clase: Ciclos.name):
await interaction.response.send_message(file=discord.File(f'Media/schedules/schedule{ciclo.name}{clase.name}.png'))
This code doesn't work, but I hope it serves to illustrate what I am trying to accomplish. The problematic part is on the function parameters, specifically on clase: Ciclos.name, I don't know how to make it depend on what the user chooses on ciclo: Ciclos.
What I've tried
I've tried to put these expressions:
clase: {Ciclos.name}
I get -> AtributeError: name
clase: Ciclos.name
I get -> AtributeError: name
clase: ciclo
I get -> NameError: name 'ciclo' is not defined. Did you mean: 'Ciclos'?
No, I didn't mean that.
Expected behavior
The expected result is this:
class ASIX example
class DAM example
In order to send the schedule image corresponding to each class:
await interaction.response.send_message(file=discord.File(f'Media/schedules/schedule{ciclo.name}{clase.name}.png'))
So I get file names like:
"scheduleASIX_1A"
"scheduleDAM_2A"
This isn't possible from a Discord side of things. The choices have to be known beforehand and synced, so they can't dynamically change based on other values (also - you can fill them in in any order, so that wouldn't even work).
You'll have to do it some other way. You can't refer to the current value of that argument as the type of the Choice.
One option could be to use Views with Select menus, for example. A more hybrid approach could be to have a slash command with Choices, and let that one answer with a Select menu for the specific options they can choose depending on their argument. There's an example for Select menus: https://github.com/Rapptz/discord.py/blob/master/examples/views/dropdown.py
Sry, I don't think dynamic choises are build into the discord api, but I usually use the following to add choises to a Slash command, maybee it can help you.
#app_commands.choices(
ciclo=[
app_commands.Choice(name="ASIX", value="ASIX"),
app_commands.Choice(name="DAM", value="DAM")
],
clase=[app_commands.Choice(name="A1", value="A1")])
I modified it to fit your example a bit to fit your example, but as said, as far as I know there is no way to make dynamic choices with the slash commands.

Solution needed to a scenario

I am trying to make use of a column's value as a radio button's choice using below code
Forms.py
#retreiving data from database and assigning it to diction list
diction = polls_datum.objects.values_list('poll_choices', flat=True)
#initializing list and dictionary
OPTIONS1 = {}
OPTIONS = []
#creating the dictionary with 0 to no of options given in list
for i in range(len(diction)):
OPTIONS1[i] = diction[i]
#creating tuples from the dictionary above
#OPTIONS = zip(OPTIONS1.keys(), OPTIONS1.values())
for i in OPTIONS1:
k = (i,OPTIONS1[i])
OPTIONS.append(k)
class polls_form(forms.ModelForm):
#retreiving data from database and assigning it to diction list
options = forms.ChoiceField(choices=OPTIONS, widget = forms.RadioSelect())
class Meta:
model = polls_model
fields = ['options']
Using a form I am saving the data or choices in a field (poll_choices), when trying to display it on the index page, it is not reflecting until a server restart.
Can someone help on this please
of course "it is not reflecting until a server restart" - that's obvious when you remember that django server processes are long-running processes (it's not like PHP where each script is executed afresh on each request), and that top-level code (code that's at the module's top-level, not in a function) is only executed once per process when the module is first imported. As a general rule: don't do ANY db query at a module's top-level or at the top-level of a class statement - at best you'll get stale data, at worse it will crash your server process (if you're doing query before everything has been properly setup by django, or if you're doing query based on a schema update before the migration has been applied).
The possible solutions are either to wait until the form's initialisation to setup your field's choices, or to pass a callable as the formfield's choices options, cf https://docs.djangoproject.com/en/2.1/ref/forms/fields/#django.forms.ChoiceField.choices
Also, the way you're building your choices list is uselessly complicated - you could do it as a one-liner:
OPTIONS = list(enumerate(polls_datum.objects.values_list('poll_choices', flat=True))
but it's also very brittle - you're relying on the current db content and ordering for the choice value when you should use the polls_datum's pk instead (which is garanteed to be stable).
And finally: since you're working with what seems to be a related model, you may want to use a ModelChoiceField instead.
For future reference:
What version of Django are you using?
Have you read up on the documentation of ModelForms? https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/
I'm not sure what you're trying to do with diction to dictionary to tuple. I think you could skip a step there and your future self will thank you for that.
Try to follow some tutorials and understand why certain steps are being taken. I can see from your code that you're rather new to coding or Python and there's room for improvement. Not trying to talk you down, but I'm trying to push you into the direction of becoming a better developer ;-)
REAL ANSWER:
That being said, I think the solution is to write the loading of the data somewhere in your form model, rather than 'loose' in forms.py. See bruno's answer for more information on this.
If you want to reload the data on each request that loads the form, you should create a function that gets called every time the form is loaded (for example in the form's __init__ function).

Odoo - Changing user group id just right after signup (ecommerce)

I'm using Odoo 10. After a new user sign up (through localhost:8069/web/signup) i want him to be automatically allocated inside a group i created on my very own custom module (the user will need authentication from an admin later on so he can be converted to a regular portal user; after signup he will receive restricted access).
I have tried many things. My latest effort looks like this:
class RestrictAccessOnSignup(auth_signup_controller.AuthSignupHome):
def do_signup(self, *args):
super(RestrictAccessOnSignup, self).do_signup(*args)
request.env['res.groups'].sudo().write({'groups_id': 'group_unuser'})
Note that I have import odoo.addons.auth_signup.controllers.main as auth_signup_controller so that I can override the auth_signup controller.
I have located that method as the responsible for doing the signup. So I call it in my new method and then try to change the newly created user's group_id.
What i miss is a fundamental understanding of how to overwrite a field's value from another model inside a controller method context. I'm using the 'request' object although i'm not sure of it. I have seen people using 'self.pool['res.users'] (e.g.) for such purposes but i don't understand how to apply it inside my problem's context.
I believe, also, that there is a way to change the default group for a user after it is created (i would like to know), but i also want to understand how to solve the general problem (accessing and overwriting a field's value from another module).
Another weird thing is that the field groups_id does exist in 'res.users' model, but it does not appear as a column in my pgAdmin interface when i click to see the 'res.users' table... Any idea why?
Thanks a lot!
i don't know if after calling :
super(RestrictAccessOnSignup,self).do_signup(*args)
you will have access to user record in request object but if so just add
the group to user like this, if not you have to find where the user record or id is saved after calling do_signup because you need to update that record to ad this group.
# create env variable i hate typing even i'm typing here ^^
env = request.env
env.user.sudo().write({'groups_id': [
# in odoo relation field accept a list of commands
# command 4 means add the id in the second position must be an integer
# ref return an object so we return the id
( 4, env.ref('your_module_name.group_unuser').id),
]
})
and if changes are not committed in database you may need to commit them
request.env.cr.commit()
Note: self.env.ref you must pass the full xmlID.
This is what worked for me:
def do_signup(self, *args):
super(RestrictAccessOnSignup, self).do_signup(*args)
group_id = request.env['ir.model.data'].get_object('academy2', 'group_unuser')
group_id.sudo().write({'users': [(4, request.env.uid)]})
In the get_object i pass as arguments the 'module' and the 'xmlID' of the group i want to fetch.
It is still not clear to me why 'ir.model.data' is the environment used, but this works as a charm. Please note that here we are adding a user to the group, and not a group to the user, and to me that actually makes more sense.
Any further elucidation or parallel solutions are welcome, the methods aren't as clear to me as they should be.
thanks.

django.views / django.models, can't delete entities with foreign key

Actually I have two things that don't seem to work. I'll list couple of models and their dependencies (shortened). The StudentGroup has students (which may be active/inactive), and messages, which are listed as chat.
In views.py, when I call delete_group(), I want to make all students inactive and delete all of the messages relevant to the group.
class StudentsGroup(models.Model):
students = models.ManyToManyField(User,limit_choices_to={'is_staff': False}, related_name="user_groups",blank=True)
finished = models.ManyToManyField(User,limit_choices_to={'is_staff': False}, related_name="finished_user_groups",blank=True)
class Message(models.Model):
group=models.ForeignKey(StudentsGroup)
def delete_group(request,group):
Message.objects.filter(group=group).delete()
groupl=StudentsGroup.objects.get(id=group)
for s in group1.students.all():
groupl.finished.add(s)
group1.save()
Nothing changes. I've tried similar things in console and it seemed to be ok. Tried bunch of similar code.
Tried to add makemigrations to the server restarting but still no result.
Kinda noob in django and webdev overall, any help would be appreciated.
In your line
Message.objects.filter(group=group).delete()
it looks like you haven't yet converted group from the raw ID value to an actual StudentGroup instance. If group is supplied to the function as a StudentGroup instance, then this should work. If, as I suspect, group is just a raw ID value, then your filter queries should be:
Message.objects.filter(group_id=group).delete()
It's nicer however to work with objects rather than IDs. Try instead doing this:
group = StudentGroup.objects.get(id=group)
Message.objects.filter(group=group).delete()
Then you can do other things like group = get_object_or_404(StudentGroup, id=group).
As for the second part, moving the Students to the group's finished list, your code looks reasonable, though you don't need the .save() part. I suspect the errors may be due to the object not being correctly instantiated yet, as with above.
However you should be able to do all this in a single line in Django 1.9+, see https://docs.djangoproject.com/en/1.10/ref/models/relations/#django.db.models.fields.related.RelatedManager.add
group1.finished.add(*list(group1.students.all()))

Django: When to customize save vs using post-save signal

I have a series of tests and cases in a database. Whenever a test is obsoleted, it gets end dated, and any sub-cases of that test should also be end dated. I see two ways to accomplish this:
1) Modify the save function to end date sub-cases.
2) Create a receiver which listens for Test models being saved, and then end dates their sub-cases.
Any reason to use one other than the other?
Edit: I see this blog post suggests to use the save method whenever you check given values of the model. Since I'm checking the end_date, maybe that suggests I should use a custom save?
Edit2: Also, for the record, the full hierarchy is Protocol -> Test -> Case -> Planned_Execution, and anytime one is end_dated, every child must also be endDated. I figure I'll end up doing basically the same thing for each.
Edit3: It turns out that in order to tell whether the current save() is the one that is endDating the Test, I need to have access to the old data and the new data, so I used a custom save. Here's what it looks like:
def save(self):
"""Use a custom save to end date any subCases"""
try:
orig = Test.objects.get(id=self.id)
enddated = (not orig.end_date) and self.end_date is not None
except:
enddated = False
super(Test, self).save()
if enddated:
for case in self.case_set.exclude(end_date__isnull=False):
case.end_date = self.end_date
case.enddater = self.enddater
case.save()
I generally use this rule of thumb:
If you have to modify data so that the save won't fail, then override save() (you don't really have another option). For example, in an app I'm working on, I have a model with a text field that has a list of choices. This interfaces with old code, and replaces an older model that had a similar text field, but with a different list of choices. The old code sometimes passes my model a choice from the older model, but there's a 1:1 mapping between choices, so in such a case I can modify the choice to the new one. Makes sense to do this in save().
Otherwise, if the save can proceed without intervention, I generally use a post-save signal.
In my understanding, signals are a means for decoupling modules. Since your task seems to happen in only one module I'd customize save.

Categories