Flask App Builder url_for views - flask-appbuilder

I am struggling on how to connect URL_for links in my app.
I have a the basic skeleton app set up.
I wish to make a link to a function (that runs code) that is built in a view (MyView).
I essentially want to pass a variable (var1) to the view 'myview/method2/var1' and have that link showing in the ContactModelView.
Thanks
class MyView(BaseView):
route_base = "/myview"
#expose('/method2/<string:var1>')
#has_access
def fun_var(self, var1):
# go to function_file and run function with var1
param1, param2 = func_file.function(var1)
self.update_redirect()
return self.render_template('method3.html',
param1=param1,param2=param2, param3=prospects)
My models.py file has the following:
class Contact(Model):
id = Column(Integer, primary_key=True)
name = Column(String(150), unique = True, nullable=False)
var1 = Column(String(150))
contact_group_id = Column(Integer, ForeignKey('contact_group.id'))
contact_group = relationship("ContactGroup")
def prospect(self):
return Markup(
'prospect')
def __repr__(self):
return self.name
I then have in views:
class ContactModelView(ModelView):
datamodel = SQLAInterface(Contact)
label_columns = {'contact_group':'Contacts Group'}
list_columns = ['name','var1','contact_group', 'action']
show_fieldsets = [
(
'Summary',
{'fields':['name','var1','contact_group', 'prospect']}
)
]

In the documentation regarding BaseView, we see that
Its constructor will register your exposed urls on flask as a Blueprint
So make sure you add the view you created, in order to 'register the blueprint'. Use something like
appbuilder.add_view_no_menu(MyView())
You can run fabmanager list-views on the console to make sure your view was registered.
As your endpoint requires a var1 parameter, you have to provide that to url_for. Something like this will work:
class Contact(Model):
var1 = Column(String(150))
...
def prospect(self):
return Markup(
'prospect')

Related

Unable to update image in Django Rest Framework , gives error " The submitted data was not a file. Check the encoding type on the form."

i was able to post the image but don't know why i am not able to update the image , i am using default form provided by DRF
i did not find any solutions yet for this one
i am uploading image via cloudinary api
the error
{
"image_1": [
"The submitted data was not a file. Check the encoding type on the form."
],
"image_2": [
"The submitted data was not a file. Check the encoding type on the form."
]
}
Model:
class MyDetail(models.Model):
name=models.CharField(max_length=50, null=True, blank=True)
image_1=models.URLField(null=True, blank=True)
image_2=models.URLField(null=True, blank=True)
Views:
class SingleDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset=MyDetail.objects.all()
serializer_class = SingleDetailSerializer
lookup_field='id'
def update(self, request, *args, **kwargs):
instance = self.get_object()
image_1 = request.FILES.get('image_1',None)
image_2 = request.FILES.get('image_2',None)
if image_1:
uploaded_image_1 = cloudinary.uploader.upload(image_1)
request.data['image_1'] = uploaded_image_1['secure_url']
if image_2:
uploaded_image_2 = cloudinary.uploader.upload(image_2)
request.data['image_2'] = uploaded_image_2['secure_url']
serializer = self.get_serializer(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response({"message": "Updated successfully.", "data": serializer.data})
def perform_update(self, serializer):
serializer.save()
serializer:
class SingleDetailSerializer(serializers.ModelSerializer):
image_1 = serializers.ImageField(max_length=None,use_url=True,required=False)
image_2 = serializers.ImageField (max_length=None,use_url=True,required=False)
class Meta:
model = MyDetail
fields = ['id','name','image_1','image_2']
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['image_1'] = instance.image_1
representation['image_2'] = instance.image_2
return representation
my DRF Form image
i even tried from my react form but it was still not working , i was not able to find solutions online and i don't know why it is not able to recognize the file though i uploaded the file. Help me to fix this
Here is how i solved it
Instead of updating image through views , i updated image directly serializer where i modified the url field to image field to upload the image
views :
class SingleDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset=MyDetail.objects.all()
serializer_class = SingleDetailSerializer
lookup_field='id'
serializer :
class SingleDetailSerializer(serializers.ModelSerializer):
image_1 = serializers.ImageField(use_url=True, required=False)
image_2 = serializers.ImageField(use_url=True, required=False)
class Meta:
model = MyDetail
fields = ['id','name','image_1','image_2']
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['image_1'] = instance.image_1
representation['image_2'] = instance.image_2
return representation
def update(self, instance, validated_data):
image_1 = validated_data.get('image_1',None)
image_2 = validated_data.get('image_2',None)
if image_1:
uploaded_image_1 = cloudinary.uploader.upload(image_1)
validated_data['image_1'] = uploaded_image_1['secure_url']
if image_2:
uploaded_image_2 = cloudinary.uploader.upload(image_2)
validated_data['image_2'] = uploaded_image_2['secure_url']
instance = super().update(instance, validated_data)
return instance

Dynamically changing trait

Is it possible to have two classes
class SimulationDigitizer(HasTraits):
width = Int(1920)
height = Int(1080)
name = 'Simulation'
class FileDigitizer(HasTraits):
Filename = File
name = 'File'
and another class 'Digitizer' having an attribute (or trait) UserDigitizer whose edition dialog will propose a drop-down list with 'Simulation' and 'File' and, depending on the choice, the instance edition of either FileDigitizer or SimulationDigitizer and get the result in UserDigitizer ?
Thanks
Thanks Jonathan, you are right, the problem is to select the appropriate subcomponent among many possible.
I ended with the following code, I guess it can be improved in many ways. I am new both to Python and Traits.
# -*- coding: utf-8 -*-
from traits.api import HasTraits, Int, File, Enum, Instance
from traitsui.api import View, Item, Handler, HGroup, InstanceEditor
class UserComponent ( HasTraits ):
""" An empty class from which all user component classes are
derived.
"""
pass
class SimulationDigitizer(UserComponent):
width = Int(1920)
height = Int(1080)
nature = 'Simulation'
class FileDigitizer(UserComponent):
filename = File
nature = 'Reading a file'
UserDigitizers = [FileDigitizer, SimulationDigitizer]
class UserComponentHandler(Handler):
def __init__(self,_user_components_dict):
Handler.__init__(self)
self._user_components_dict = _user_components_dict
def object_user_component_nature_changed ( self, info ):
# Find new UserComponent class from string in user_component_nature
new_user_component = self._user_components_dict[info.object.user_component_nature]
# If different, change user_component value
if info.object.user_component is not new_user_component:
info.object.user_component = new_user_component
class Digitizer(HasTraits):
user_component_nature = Enum([x().nature for x in UserDigitizers])
_user_file_digitizer = FileDigitizer()
_user_simulation_digitizer = SimulationDigitizer()
# Dictionary with keys = nature and values = user digitizers
_user_digitizers_dict = {x.nature: x for x in [_user_file_digitizer,_user_simulation_digitizer]}
user_component = Enum(_user_file_digitizer,_user_simulation_digitizer)
view = View(HGroup(Item('user_component_nature',
label = 'Nature'),
Item('user_component',
show_label = False,
editor = InstanceEditor(label = 'Edit',
kind = 'modal'))),
handler = UserComponentHandler(_user_digitizers_dict))
d = Digitizer()
if __name__ == '__main__':
d.configure_traits()

Test fails in tests.py but succeeds in python shell

I'm a newbee to python and django and I can't figure out what I'm doing wrong here.
I have a Site object:
class Site (models.Model):
domain = models.CharField(max_length=30)
support_status = models.CharField(max_length=20, choices= SITE_SUPPORTED_STATUS, blank=False)
requests = models.IntegerField()
objects = SiteManager()
def __unicode__(self):
return u'%s %s' % (self.domain, self.support_status)
And a SiteManager object
class SiteManager(models.Manager):
def supported_site_counts(self):
i = self.filter(support_status__iexact="SUPPORTED").count()
return i
From the console, the method "supported_site_counts()" works just fine
>>(InteractiveConsole)
>>> from bookmark.models import Site, SiteManager
>>> Site.objects.supported_site_counts()
>>>>2012-05-18 18:09:20,027 DEBUG (0.001) SELECT COUNT(*) FROM "bookmark_site" WHERE
>>>>"bookmark_site"."support_status" LIKE SUPPORTED ESCAPE '\' ; args=(u'SUPPORTED',)
>>>>2012-05-18 18:09:20,028 DEBUG Got 1 supported site
>>>>1
But when it's called from a testcase, the count returns as 0
class SiteManagerTest(unittest.TestCase):
def test_supported_site_counts(self):
self.x = False
self.count = Site.objects.supported_site_counts()
logging.debug(self.count)
This is probably because the tests will set up a database separate from your development database to run the tests in. You will need to put testing data in to the testing database, either programmatically or using fixtures.

Deleting SQL data in associated OneToOneField model from admin

I've got a model that references another model via OneToOneField so that when you use Django's built-in delete_selected admin action, the associated model's data is not deleted. I'd like to write a custom admin action to delete the data in that associated model as well.
Here's my model:
class Party(models.Model):
TYPE_CHOICES=(
('P','Person'),
('O','Organization')
)
partyType = models.CharField(max_length=1, choices=TYPE_CHOICES)
name = models.CharField(max_length=100)
comment = models.CharField(max_length=500,blank=True)
accessIdCrossRef=models.IntegerField(blank=True, null=True)
mailingLists = models.ManyToManyField(MailingList)
inMainList=models.BooleanField(default=False)
inSubList=models.BooleanField(default=False)
class Meta:
db_table='party'
ordering=['name',]
def __unicode__(self):
return self.name
class Person(models.Model):
party = models.OneToOneField(Party, editable=False)
firstName=models.CharField(max_length=60)
lastName=models.CharField(max_length=60)
...
def save(self):
if None == self.party :
print 'Creating party for person'
p = Party()
p.partyType = 'P'
p.save()
self.party = p
# Get address to set party name used in list
city=""
state=""
postalCode=""
try:
partyAddress = PartyPostalAddress.objects.get(party=self.party)
address = partyAddress.postalAddress
city=address.city
state=address.state
postalCode=address.postalCode
except PartyPostalAddress.DoesNotExist:
pass
self.party.name = '%s, %s - %s, %s %s' %(self.lastName, self.firstName, city, state, postalCode)
self.party.save()
super(Person,self).save()
My assumption was to write a def delete() in my model like this:
def delete(self):
self.party.delete()
self.delete()
And an admin action like so:
class PersonAdmin(admin.ModelAdmin):
list_display = ('lastName','firstName')
search_fields = ('firstName', 'lastName')
actions=['really_delete_selected']
def get_actions(self, request):
actions = super(PersonAdmin, self).get_actions(request)
del actions['delete_selected']
return actions
def really_delete_selected(self, request, queryset):
for obj in queryset:
obj.delete()
if queryset.count() == 1:
message_bit = "1 person was"
else:
message_bit = "%s people were" % queryset.count()
self.message_user(request, "%s successfully deleted." % message_bit)
really_delete_selected.short_description = "Delete selected entries"
That deletes person.party and most of person, but throws an error because person's party OneToOneField is now empty. The specific error is:
"AssertionError at /admin/common/person/
Party object can't be deleted because its id attribute is set to None."
Any ideas? This, this, and this question are related, but only one of them utilizes the OneToOneField and he did that erroneously.
I am getting a feeling that it should be as simple as switching the sequence of deleting the two (unless you have tried this already). Since the person is associated with party, once you delete person, you cannot access party. Hence you should do
person.party.delete()
person.delete()
Got it cleaned up and working!
My model:
class Party(models.Model):
name = models.CharField(max_length=100)
...
class Person(models.Model):
party = models.OneToOneField(Party, editable=False)
firstName=models.CharField(max_length=60)
lastName=models.CharField(max_length=60)
def delete(self):
d = self.party.id
Party.objects.get(id__exact=d).delete()
My admin:
class PersonAdmin(admin.ModelAdmin):
actions=['really_delete_selected']
def get_actions(self, request):
actions = super(PersonAdmin, self).get_actions(request)
del actions['delete_selected']
return actions
def really_delete_selected(self, request, queryset):
for obj in queryset:
obj.delete()
if queryset.count() == 1:
message_bit = "1 person was"
else:
message_bit = "%s people were" % queryset.count()
self.message_user(request, "%s successfully deleted." % message_bit)
really_delete_selected.short_description = "Delete selected entries"
...

Django comments app, getting content type

I am trying to create a comments application to use it everywhere where I need it, so I geuss I have to use ContentType to attach comments to different models of my project.
so here:
my model:
class Comment(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
text = models.TextField((u'Текст комментария'))
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
my view:
def add_comment(request):
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
new_comment = Comment()
new_comment.text = request.POST['text']
new_comment.content_type = ???
new_comment.object_id = request.POST['object_id']
new_comment.user = request.user
new_comment.save()
return HttpResponseRedirect(request.META['HTTP_REFERER'])
else: ...
How can I get a content type of the current model I am working with?
I have app NEWS and model Post in it, so I want to comments my Posts.
I know I can use ContentType.objects.get(app_label="news", model="post"), but I am getting exact value, so in that way my comment app will not be multipurpose.
P.S. sorry for bad English.
Check django.contrib.comments.forms.CommentForm.get_comment_create_data: It returns a mapping to be used to create an unsaved comment instance:
return dict(
content_type = ContentType.objects.get_for_model(self.target_object),
object_pk = force_unicode(self.target_object._get_pk_val()),
user_name = self.cleaned_data["name"],
user_email = self.cleaned_data["email"],
user_url = self.cleaned_data["url"],
comment = self.cleaned_data["comment"],
submit_date = datetime.datetime.now(),
site_id = settings.SITE_ID,
is_public = True,
is_removed = False,
)
So I guess that the line your are looking for is:
content_type = ContentType.objects.get_for_model(self.target_object),
Remenber, self is the form instance, and self.target_object() returns the instance that the current comment is attached to.