Django: how to get value from model in view - django

I have a view that will conditionally display a breadcrumb trail based on the value of the object's "status" field. This works if I manually set the status value (ex status = "completed"). However, as a newbie, I can't figure out how to retrieve the value?
status = Project.status is not working.
Here is the view:
class CompanyProjectsDetailView(DetailBreadcrumbMixin, UpdateView):
model = Project
queryset = Project.objects.get_with_counted_notes_documents_todos()
template_name = 'company_accounts/project_detail.html'
context_object_name = 'project'
form_class = ProjectStatusForm
status = Project.status
if status == "completed":
#cached_property
def crumbs(self):
return [
("projects", reverse(
"company_project:" + CompanyProjects.list_view_name, )
),
(f"completed projects", reverse(
"company_project:" + CompanyProjects.list_view_name, )
),
]

I figured out a way to get this to work. The key is getting the instance in the crumbs method. I imagine there may be a more elegant way to accomplish this.
The working view:
class CompanyProjectsDetailView(DetailBreadcrumbMixin, UpdateView):
model = Project
queryset = Project.objects.get_with_counted_notes_documents_todos()
template_name = 'company_accounts/project_detail.html'
context_object_name = 'project'
form_class = ProjectStatusForm
# pk_url_kwarg = 'project_id'
#cached_property
def crumbs(self):
project = self.get_object()
if project.status == "completed":
return [
("projects", reverse(
"company_project:" + CompanyProjects.list_view_name, )
),
(f"completed projects", reverse(
"company_project:completed_projects" )
),
(f"{project.title}",
reverse(
"company_project:" + CompanyProjectsDetailView.detail_view_name,
kwargs={'pk': project.id})
),
]
elif project.status == "paused":
return [
("projects", reverse(
"company_project:" + CompanyProjects.list_view_name, )
),
(f"paused projects", reverse(
"company_project:paused_projects" )
),
(f"{project.title}",
reverse(
"company_project:" + CompanyProjectsDetailView.detail_view_name,
kwargs={'pk': project.id})
),
]
else:
return [
("projects", reverse(
"company_project:" + CompanyProjects.list_view_name, )
),
(f"{project.title}",
reverse(
"company_project:" + CompanyProjectsDetailView.detail_view_name,
kwargs={'pk': project.id})
),
]

Related

Properly configure TrigramSimilarity and SearchVector for searching users

I have written a search function in order to do FTS on my user model however, I am having a hard time figuring out how to configure it in order to get similar results as well, for instance, if the username contains MOST character of the search query it should display it as well. for instance if I search for bob and there is a user with username bobuser13 it should be displayed as well.
Currently, my search function is:
def search(self, search_text):
search_vectors = (
SearchVector(
'username', weight='A', config='english'
) + SearchVector(
'last_name' , weight='B', config='english'
) + SearchVector(
'first_name' , weight='C', config='english'
)+ SearchVector(
'first_name','last_name', weight='D', config='english'
) + + SearchVector(
'bio', weight='D', config='english'
)
)
search_query = SearchQuery(
search_text, config=' english'
)
search_rank = SearchRank(search_vectors,search_query)
trigram = TrigramSimilarity(
'username', search_text
) + TrigramSimilarity(
'last_name',search_text
) + TrigramSimilarity(
'first_name',search_text
)
qs = (
self.get_queryset()
.filter(sv=search_query)
.annotate(rank=search_rank, trigram=trigram, bs=Greatest('rank','trigram'))
.filter(Q(bs__gte=0.1))
.order_by('-bs')
)
return qs
And my user model is:
class Profile(AbstractUser):
bio = models.TextField()
sv = pg_search.SearchVectorField(null=True)
objects = ProfileManager()
class Meta:
indexes = [
GinIndex(fields=['sv'],name='search_idx_user'),
]
def __str__(self):
return self.username
def get_absolute_url(self):
return "{}".format(self.slug)
how can I configure this so that it also includes similar names as well?

Django redirect if User has created object

in my model the USER will create the object startup_name, however, i want to carry out a check when user click the button again that of he has created the object so he will be redirected to another page.
class Startup ( models.Model ) :
author = models.OneToOneField ( User , on_delete = models.CASCADE )
startup_name = models.CharField ( 'Startup Name' , max_length = 32 , null = False , blank = False )
class startupform(forms.ModelForm):
class Meta:
model = Startup
fields = ('startup_name',)
widgets = {
'startup_name': forms.TextInput(attrs = {'class':'form-control'}),
}
def clean(self):
super ( ).clean ( )
startup_name = self.cleaned_data.get ( 'startup_name' )
startup_qs = Startup.objects.filter ( startup_name = startup_name )
if startup_qs.exists ( ):
raise forms.ValidationError ( 'This Startup Already Exist!' )
#login_required
def create_startupform(request) :
q = Startup.objects.all()
if q.exists():
return redirect ( 'str_detailedview' )
else:
form = startupform ( request.POST or None )
if form.is_valid ( ) :
instance = form.save (commit = False)
instance.author = request.user
instance.save()
return redirect ( 'str_detailedview' )
else:
form = startupform()
return render ( request , 'str_name.html' , { 'form' : form } )
you need check input name into Startup model and if its exist then you can redirect:
#login_required
def create_startupform(request) :
if request.method == 'POST' :
form = startupform ( request.POST )
if form.is_valid ( ) :
startup_name_input = request.POST.get('startup_name')
if Startup.objects.filter(startup_name='startup_name_input').exists():
return render(request, 'some_template.html', {'form' : form})
result = form.save ( commit = False )
result.author = request.user
result.save ( )
return redirect ( 'test', startup_id = result.pk)
else :
form = startupform ( )
return render ( request , 'str_name.html' , { 'form' : form } )

DJANGO <OPTION> element with EXTRA ATTRIBUTES

How can we add some extra tags to DJANGO FORM MODEL tag element? I all-read tried change something inside form.py/class META/widgets but without nothing.
class MySelect( forms.Select ):
def __init__( self, attrs = None, choices = (), option_xtra_attr = '' ):
self.option_xtra_attr = option_xtra_attr
super( MySelect, self ).__init__( attrs, choices )
def render_option( self, selected_choices, option_value, option_label, option_xtra_attr = '' ):
if option_value is None:
option_value = ''
option_value = force_text( option_value )
if option_value in selected_choices:
selected_html = mark_safe( ' selected="selected"' )
if not self.allow_multiple_selected:
# Only allow for a single selection.
selected_choices.remove( option_value )
else:
selected_html = ''
return format_html( '<option value="{}"{}{}>{}</option>',
option_value,
selected_html,
option_xtra_attr,
force_text( option_label ) )
class MonitoringSpot_InLine_FORM( forms.ModelForm ):
class Meta:
model = MonitoringSpotClass
fields = [ 'monitoringSpot_NODE_monitoringAreaType', ]
widgets = {
'monitoringSpot_NODE_monitoringAreaType': MySelect( option_xtra_attr = { 'xdata': 'value' } )
}
It's works better
class OptionAttr( forms.Select ):
def __init__( self, *args, **kwargs ):
self.src = kwargs.pop( 'attributes', { } )
super().__init__( *args, **kwargs )
def create_option( self, name, value, label, selected, index, subindex = None, attrs = None ):
splitedLabel = label.split(",")
options = super( OptionAttr, self ).create_option( name, value, label, selected, index, subindex = None, attrs = None )
for k, v in self.src.items():
if v != True:
options[ 'attrs' ][ k ] = v
else:
options[ 'attrs' ][ k ] = splitedLabel[1:]; options[ 'label' ] = str(splitedLabel[0])
return options
class MonitoringSpot_InLine_FORM( forms.ModelForm ):
class Meta:
model = MonitoringSpotClass
fields = [ 'monitoringSpot_NODE_monitoringAreaType', ]
widgets = {
'monitoringSpot_NODE_monitoringAreaType': OptionAttr( attributes = { 'extra': True } )
}
If you set True to extra attribute this code will split all data from LABEL into a extra tag. Or you can set your own value.

Django 2.0.7. is missing the complete path in url when the user try to upload a file. It works on local enviroment but not in production server

I have a model with a ImageField:
class Usr( User ):
idusuario = models.AutoField( primary_key = True )
usuario = models.CharField( blank = False, unique = True, max_length = 50 )
contraseña = models.CharField( blank = False, max_length = 250 )
telefono = models.CharField( max_length = 15, blank = True, null = True )
celular = models.CharField( max_length = 15, blank = True, null = True )
fotografia = models.ImageField( blank = True, null = True, upload_to = 'usuarios' )
depende_de = models.ForeignKey( 'self', on_delete = models.CASCADE, related_name = '+', blank = True, null = True )
def __unicode__( self ):
return self.get_full_name()
def __str__( self ):
return self.get_full_name()
And its form (a ModelForm ):
class RegUsuario( forms.ModelForm ):
class Meta:
model = Usr
fields = [
'usuario',
'contraseña',
'is_active',
'is_superuser',
'first_name',
'last_name',
'email',
'telefono',
'celular',
'fotografia',
'groups',
'depende_de'
]
In views (vw_usuario.py) I have:
#valida_acceso( [ 'usr.agregar_usuarios_usuario' ] )
def new( request ):
if 'POST' == request.method:
frm = RegUsuario( request.POST, files = request.FILES )
if frm.is_valid():
obj = frm.save( commit = False )
obj.username = obj.usuario
obj.set_password( obj.contraseña )
obj.save()
for g in request.POST.getlist( 'groups' ):
obj.groups.add( g )
obj.save()
return HttpResponseRedirect( reverse( 'usuario_ver', kwargs = { 'pk' : obj.pk } ) )
frm = RegUsuario( request.POST or None )
return render( request, 'global/form.html', {
'menu_main' : Usr.objects.filter( id = request.user.pk )[ 0 ].main_menu_struct(),
'footer' : True,
'titulo' : 'Usuarios',
'titulo_descripcion' : 'Nuevo',
'frm' : frm
} )
And in urls.py:
urlpatterns = [
...
path( 'usuarios/nuevo/', vw_usuario.new, name = "usuario_nuevo" ),
...
]
If I go to http://example.com/usuarios/nuevo/ in the browser I can the form displayed as well, then I fill the fields and submit the form, and I got the exception:
Page not found (404)
Request Method: POST
Request URL: http://example.com/usuarios/nuevo/
Raised by: seguridad.mkitsafe.validacion
Using the URLconf defined in example.urls, Django tried these URL patterns, in this order:
...
usuarios/eliminar/<pk>/ [name= usuario_eliminar ]
usuarios/nuevo/ [name= usuario_nuevo ]
usuarios/<pk>/ [name= usuario_ver ]
...
The current path, nuevo/, didn t match any of these.
I don't understand why the url is taken as nuevo/ instead of usuarios/nuevo/
In the form template I'm setting method = "post", enctype="multipart/form-data" and action="" (I've also tried action="usuarios/nuevo" and action="http://example.com/usuarios/nuevo/")
The path for MEDIA_ROOT exists and has enough perms.
The issue happens if I fill in the form the ImageField field or not.
I noticed that if I remove the field in the modelform, everything works as well.
The source code for seguridad.mkitsafe.validacion is:
def valida_acceso( permisos = None ):
url_error = 'seguridad_inicio'
url_autenticacion = 'seguridad_login'
def _valida_acceso( vista ):
def validacion( *args, **kwargs ):
usuario = args[ 0 ].user
if not usuario.is_authenticated:
print_error( "Vista {} negada por autenticación".format( vista.__name__ ), "Exec Info" )
return HttpResponseRedirect( reverse( url_autenticacion ) )
if permisos is None:
return vista( *args, **kwargs )
perms = []
for perm in permisos:
permiso = Permiso.get_from_package_codename( perm )
if( permiso is None ):
print_error( "No se ha encontrado el permiso: " + perm )
else:
perms.append( permiso.perm() )
desc = permiso.descendencia()
for p in desc:
perms.append( p.perm() )
for perm in perms:
p = "{}.{}".format( perm.content_type.app_label, perm.codename )
if usuario.has_perm( p ):
return vista( *args, **kwargs )
print_error( "Vista {} negada por permisos {}".format( vista.__name__, permisos ), "Exec Info" )
return HttpResponseRedirect( reverse( url_error ) )
return validacion
return _valida_acceso
And it is a decorator which verify perms and authentication.
If I remove this decorator the excepion changes in the Raised by to seguridad.vw_usuario.new
Page not found (404)
Request Method: POST
Request URL: http://example.com/usuarios/nuevo/
Raised by: seguridad.vw_usuario.new
Using the URLconf defined in example.urls, Django tried these URL patterns, in this order:
admin/
...
usuarios/actualizar/<pk>/ [name='usuario_actualizar']
usuarios/eliminar/<pk>/ [name='usuario_eliminar']
usuarios/nuevo/ [name='usuario_nuevo']
usuarios/<pk>/ [name='usuario_ver']
usuarios/ [name='usuario_inicio']
...
The current path, nuevo/, didn't match any of these.
I also noticed that when the error is raised and the decorator is active the decorator or the view function is not called.
I also tried to copy a file in MEDIA_ROOT path with an script and it worked as well, so the script has right access to this path.
Any comment about the issue?

Flask-admin UserWarning: Fields missing from ruleset

When executing my Flask application I get the following warnings:
C:\Python27\lib\site-packages\flask_admin\model\base.py:1324: UserWarning: Fields missing from ruleset: password
warnings.warn(text)
C:\Python27\lib\site-packages\flask_admin\model\base.py:1324: UserWarning: Fields missing from ruleset: new_password
warnings.warn(text)
* Restarting with stat
C:\Python27\lib\site-packages\flask_admin\model\base.py:1324: UserWarning: Fields missing from ruleset: password
warnings.warn(text)
C:\Python27\lib\site-packages\flask_admin\model\base.py:1324: UserWarning: Fields missing from ruleset: new_password
warnings.warn(text)
I've normally used form_excluded_columns to remove unwanted fields from my form, but this time I have a hard time to get rid of those errors.
Here's my view:
class AdministratorView(sqla.ModelView):
page_size = 10
column_searchable_list = (
'username',
'description'
)
column_list = (
'username',
'apikey',
'description',
'active'
)
column_exclude_list = list = (
'apikey',
'source'
)
form_excluded_columns = (
'source',
'photos'
)
column_labels = {
'apikey': 'API Key'
}
form_widget_args = {
'apikey':{
'readonly':True
}
}
form_create_rules = (
rules.FieldSet(('username', 'password', 'description'), 'Personal'),
rules.FieldSet(('roles', 'apikey', 'active'), 'Permission'),
)
form_edit_rules = (
rules.FieldSet(('username', 'description'), 'Personal'),
rules.FieldSet(('roles', 'apikey', 'active'), 'Permission'),
rules.Header('Reset password'),
rules.Field('new_password')
)
def on_model_change(self, form, model, is_created):
if is_created is False:
if form.new_password.data:
model.password = generate_password_hash(form.new_password.data)
def scaffold_form(self):
form_class = super(AdministratorView, self).scaffold_form()
form_class.password = fields.PasswordField('Password', [validators.Required()])
form_class.new_password = fields.PasswordField('New Password')
return form_class
def is_accessible(self):
if login.current_user.is_authenticated:
return login.current_user.has_role('admin')
The purpose of this view is to have a single, required Password-field on the create form and a optional "New password"-field on the edit-form. I understand that the warnings arise when I don't include password/new_password in form_create_rules and form_edit_rules, but adding those fields to form_excluded_columns doesn't fix it.
Any tips on how I can get rid of the warnings?
Edit:
I suppose I should rather use get_create_form and get_edit_form instead of only scaffold_form. One benefit is that this makes it easier to override each form separately. Can I simplify this further? Should I do requirement validation like this or add nullable=False to the database schema (SQLAlchemy)?
class AdministratorView(sqla.ModelView):
page_size = 10
column_searchable_list = (
'username',
'description'
)
column_list = (
'username',
'apikey',
'description',
'active'
)
column_exclude_list = list = (
'apikey',
'source'
)
form_excluded_columns = (
'source',
'photos'
)
column_labels = {
'apikey': 'API Key'
}
form_widget_args = {
'apikey':{
'readonly':True
}
}
form_create_rules = (
rules.FieldSet(('username', 'password', 'description'), 'Personal'),
rules.FieldSet(('roles', 'apikey', 'active'), 'Permission'),
)
form_edit_rules = (
rules.FieldSet(('username', 'description'), 'Personal'),
rules.FieldSet(('roles', 'apikey', 'active'), 'Permission'),
rules.Header('Reset password'),
rules.Field('new_password')
)
def get_create_form(self):
form = self.scaffold_form()
form.username = fields.StringField('Username', [validators.Required()])
form.password = fields.PasswordField('Password', [validators.Required()])
return form
def get_edit_form(self):
form = self.scaffold_form()
delattr(form, 'password')
form.new_password = fields.PasswordField('New Password')
return form
def on_model_change(self, form, model, is_created):
if is_created is False:
if form.new_password.data:
model.password = generate_password_hash(form.new_password.data)
def is_accessible(self):
if login.current_user.is_authenticated:
return login.current_user.has_role('admin')
Perhaps this will help: How can I avoid Flask-Admin 2.1 warning "UserWarning: Fields missing from ruleset"?
Here's the relevant code from that answer:
import warnings
with warnings.catch_warnings():
warnings.filterwarnings('ignore', 'Fields missing from ruleset', UserWarning)
admin.add_view(UserView())