Writing custom url model field in Django - django

I am creating one model called Profile in which i have to add a url field for telegram profile. It takes username as input, but in output it should look like this: https://t.me/{username}.
How I can create custom model field for this problem. Thanks by the way
My expectation is that, you only enter username, but in output it comes with prefix https://t.me/ and full url path will be https://t.me/{username}

Create a property function in your profile model.
#property
def get_telegram_link(self):
return f"https://t.me/{self.telegram_username}"
When accessing the model link on your template or code use:
profile_instance.get_telegram_link()

create a function under your model and use it in the template:
def get_tg_link(self):
return f"https://t.me/{self.telegram_username}"
or override save function under your model
def save(self, *args, **kwargs):
self.telegram_profile = f"https://t.me/{self.tg_username}"
super().save(*args, **kwargs)

Related

Concatenate value of two models by overriding ModelForm and ModelChoiceField

To show just the just the related Projects in a ForeignKey Selectbox in Django AdminForm, i customized my ActionAdmin Model with a ActionAdminForm class. to preselect values i used a class like posted here https://stackoverflow.com/a/9191583/326905. Thanks a lot, this works really fine.
But when user does not navigate form Customer -> Project -> Action and navigates directly to Actions in django admin i want to display the values in the selectbox for foreignkey project in ActionAdmin Form formatted like this:
Customername1 - Projectname1
Customername1 - Projectname2
Customername2 - Projectname3
My question is, how could i override self.fields["project"]
in the else case in the code below, so that i get selectbox values concatenated from Project.customer.name and Project.name?
class ActionAdminForm(ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(ActionAdminForm, self).__init__(*args, **kwargs)
if self.request.GET.get('project'):
prj = Project.objects.get(id=self.request.GET.get('project'))
self.fields["project"].queryset = Project.objects.filter(customer = prj.customer)
else:
self.fields["project"] = ProjectModelChoiceField(Project.objects.all().order_by('name'))
class Meta:
model = Action
I got the solution. Yeah. First i got always error when i tried to use just self.fields["project"], but now it works. I put it into else and wrote a ProjectModelChoiceField like below, influenced by this description: http://bradmontgomery.blogspot.de/2009/01/custom-form-for-djangos-automatic-admin.html
class ProjectModelChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return "%s - %s"%(obj.customer.name, obj.name)

Custom Query for Django ModelChoiceField using user.get_profile()

I am wondering how to access a user's profile when creating the
queryset for a ModelChoiceField. I would like to be able to use the
ModelChoiceField to display contacts from another table based on a
parameter saved in the user profile i.e.
who = forms.ModelChoiceField(queryset=Contacts.objects.filter(id__exact=request.user.get_profile().main_company))
Is there a better way to do this (beyond an ajax picker in the
template)?
Greg
For Those interested I was able to come up with a solution from the following SO discussions:
How do I access the request object or any other variable in a form's clean() method?
Django: accessing the model instance from within ModelAdmin?
class InspectionRequestForm(ModelForm):
....
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(InspectionRequestForm, self).__init__(*args, **kwargs)
companyid = self.request.user.get_profile().main_contactnum.clientid.idflcustomernum
self.fields['who'].queryset = Contacts.objects.filter(clientid__exact=companyid)
My View:
Save Form (Not as necessary to include request=request here, but just in case)
form = InspectionRequestForm(request.POST, request=request)
Or Empty Form
form = InspectionRequestForm(request=request)
Thanks to Daniel Roseman for both of the previous answers.
https://stackoverflow.com/users/104349/daniel-roseman

adding new form fields dynamically in admin

I am trying to add dynamically new form fields (I used this blog post), for a form used in admin interface :
class ServiceRoleAssignmentForm(forms.ModelForm):
class Meta:
model = ServiceRoleAssignment
def __init__(self, *args, **kwargs):
super(ServiceRoleAssignmentForm, self).__init__(*args, **kwargs)
self.fields['test'] = forms.CharField(label='test')
class ServiceRoleAssignmentAdmin(admin.ModelAdmin):
form = ServiceRoleAssignmentForm
admin.site.register(ServiceRoleAssignment, ServiceRoleAssignmentAdmin)
However, no matter what I try, the field doesn't appear on my admin form ! Could it be a problem related to the way admin works ? Or to ModelForm ?
Thank for any help !
Sébastien
PS : I am using django 1.3
When rendering your form in template, fields enumerating from fieldsets variable, not from fields. Sure you can redefine fieldsets in your AdminForm, but then validations will fail as original form class doesn't have such field. One workaround I can propose is to define this field in form definition statically and then redefine that field in form's init method dynamically. Here is an example:
class ServiceRoleAssignmentForm(forms.ModelForm):
test = forms.Field()
class Meta:
model = ServiceRoleAssignment
def __init__(self, *args, **kwargs):
super(ServiceRoleAssignmentForm, self).__init__(*args, **kwargs)
# Here we will redefine our test field.
self.fields['test'] = forms.CharField(label='test2')
I actually have a the same issue which I'm working through at the moment.
While not ideal, I have found a temporary workaround that works for my use case. It might be of use to you?
In my case I have a static name for the field, so I just declared it in my ModelForm. as normal, I then override the init() as normal to override some options.
ie:
def statemachine_form(for_model=None):
"""
Factory function to create a special case form
"""
class _StateMachineBaseModelForm(forms.ModelForm):
_sm_action = forms.ChoiceField(choices=[], label="Take Action")
class Meta:
model = for_model
def __init__(self, *args, **kwargs):
super(_StateMachineBaseModelForm, self).__init__(*args, **kwargs)
actions = (('', '-----------'),)
for action in self.instance.sm_state_actions():
actions += ((action, action),)
self.fields['_sm_action'] = forms.ChoiceField(choices=actions,
label="Take Action")
if for_model: return _StateMachineBaseModelForm
class ContentItemAdmin(admin.ModelAdmin):
form = statemachine_form(for_model=ContentItem)
Now as I mentioned before, this is not entirely 'dynamic', but this will do for me for the time being.
I have the exact same problem that, if I add the field dynamically, without declaring it first, then it doesn't actually exist. I think this does in fact have something to do with the way that ModelForm creates the fields.
I'm hoping someone else can give us some more info.
Django - Overriding get_form to customize admin forms based on request
Try to add the field before calling the super.init:
def __init__(self, *args, **kwargs):
self.fields['test'] = forms.CharField(label='test')
super(ServiceRoleAssignmentForm, self).__init__(*args, **kwargs)

How can I send variables to my forms on init in Django?

I want to send variables to a form in my Django project so that my form's save method associates the correct object with the foreign key in the model.
I tried setting it in the init method, but that doesn't seem to work.
Here is my Form's init:
def __init__(self, rsvp, max_guests=2, *args, **kwargs):
super(RSVPForm, self).__init__(*args, **kwargs)
self.rsvp = rsvp
self.max_guests = rsvp.max_guests
I think you may be looking for initial:
Use initial to declare the initial value of form fields at runtime. For example, you might want to fill in a username field with the username of the current session.
Pulling directly from the docs:
class CommentForm(forms.Form):
name = forms.CharField(initial='class')
url = forms.URLField()
comment = forms.CharField()
f = CommentForm(initial={'name': 'instance'})
This would yield a form with the initial value of name being 'instance'.

Readonly fields in the django admin/inline

I use this snippet to show several fields in my admin backend as readonly, but as noticed in the comments, it does not work on stackedinline/tabularinline. Is there any other way to achieve this? I have a list of objects attached to a model and just want to show it in the model's details view without the possibility to change values.
If you are running Django 1.3 or later; there's an attribute named ModelAdmin.readonly_fields which you could use.
InlineModelAdmin inherits from ModelAdmin, so you should be able to use it from your inline subclass.
I've encountered the same problem today. Here is my solution. This is example of read-only field for the ForeignKey value:
class MySelect(forms.Select):
def render(self, name, value, attrs=None, choices=()):
s = Site.objects.get(id=value)
return s.name
class UserProfileInlineForm(forms.ModelForm):
site = forms.ModelChoiceField(queryset=Site.objects.all(), widget=MySelect)
class UserProfileInline(admin.StackedInline):
model = UserProfile
form = UserProfileInlineForm
As is the case with JQuery, it seems you can achieve this by changing an attr called "disabled" (works in my Safari, OK we're now in 2013 :-) ).
Example below:
def get_form(self, request, obj=None, **kwargs):
result = super(<your ModelAdmin class here>, self).get_form(request, obj=obj, **kwargs)
result.base_fields[<the select field you want to disable>].widget.attrs['disabled'] = 'disabled'
return result