How to set assignee to ticket in Zenpy python client library - python

I am integrating Zendesk ITSM API in my python library using Zenpy client.
For creating ticket using zenpy client , I can set reporter of ticket by email id, but for assignee I am not able to set assignee by email id.
This is the code I have tried so far.
ticket_payload = Ticket(
description="some description",
type="task",
priority="high",
status="open"
)
ticket_payload.requester = User(email="requester1#gmail.com"])
ticket_payload.assignee = User(email="assignee1#gmail.com")
response = self.zenpy_client.tickets.create(ticket_payload)
Response ticket I get has reporter set, but assigneee is None.
If I pass id along with the email as
ticket_payload.assignee = User(id= 354876354,email="assignee1#gmail.com")
then it works and I can see assignee is set to ticket. But this is not required for reporter.
Is this the defult behaviour of zenpy, or am I missing something?

It took me a while but I think I understand your issue. From the doc in the API Objects section under the Object Properties section:
When the assignee attribute is accessed, Zenpy first attempts to
locate the related User in the User cache and if it cannot be found
will generate and execute an API call to retrieve, instantiate, cache
and return the object.
I mistakenly assumed that is meant I could set the value of the assignee attribute and zenpy would look it up and then put the id in the assignee_id field. This is an incorrect interpretation. The quote means if you set the assignee_id and then attempt to access the assignee attribute it will look it up and return it. But there must be an id.
From the next section of the docs:
It is important to note that most property setters throw away all
information except for the id. This is because Zendesk only expects
the id, so any modifications made to the object will not be persisted
automatically.
So when you set the assignee or requestor without an id, the email address is thrown away and the respective id is set to None.
As to why the requester ID is set, it is probably set to the User that you use to authenticate the request rather than the one that you specify.

Related

Is there a way to make the 'One' table optional in OneToManyRelationship in Django

I have two tables, one is Anonym the other is Userdatabase. I want my app to work without requiring any login info therefore it will work with Anonym only by using the deviceid of the user to process account information. If however, a user wants to access extra features they need to create a user with username/password. Then I will process the data using Userdatabase table. A user can have multiple devices so there is a OneToMany relationship in there, but a device doesn't have to have a User (they don't need to register) which breaks the relationship. Is there a way to make the Userdatabase table optional while keeping the OneToMany relationship? Perhaps by inserting a method or another class within UserDatabase? Please find the code below:
--Models--
class Anonym(models.Model):
deviceid=models.ForeignKey(Userdatabase,max_length=200,on_delete=models.SET_NULL,null=True)
accounttype=models.TextField(default='Free')
numberofattempts=models.IntegerField(default=0)
created=models.DateField(auto_now_add=True)
class Userdatabase(models.Model):
username=models.CharField(max_length=20,unique=True)
password=models.CharField(max_length=20)
deviceid=models.TextField(default='inputdeviceid')
accounttype=models.TextField(default='Free')
numberofattempts=models.IntegerField(default=0)
created=models.DateField(auto_now_add=True)
--urls--
urlpatterns=[path('deviceregister/<str:id>/',views.deviceregistration)]
--views--
def deviceregistration(request,id):
import time
deviceid=id
newdevice-models.Anonym(created=time.strftime("%Y-%m-%d"),deviceid=deviceid)
newdevice.save()
return HttpResponse('Succesful registration')
When I send a request as '/deviceregister/123456/' for example, django raises an ValueError saying Cannot assign "'123456'": "Anonym.deviceid" must be a "Userdatabase" instance.
you should search by fieldname, which contains id. in your case it is deviceid_id.
newdevice=models.Anonym(created=time.strftime("%Y-%m-%d"),deviceid_id=deviceid)
deviceid in your case should be Userdatabase.objects.get(pk=id)
deviceid=Userdatabase.objects.get(pk=id)
newdevice=models.Anonym(created=time.strftime("%Y-%m-%d"),deviceid=deviceid)
in my opinion - field names in your project really can confuse anyone
If you do not want to change your model, you can just link any newly-added device to a dummy user. When later a user want to link a device, replace dummy with the real user.
If you can change your model, you can remove the foreign key relationship, and add another table which links the id of both side: one field for deviceid and the other userid.
I know both options kind of smell, but at least they should work :)

Django save or update model

I am using Django 1.5.1 and I want to save or update model.
I read the django document and I met the get_or_create method which provides saving or updating. There is a usage like;
Model.objects.get_or_create(name='firstName',surname='lastName',defaults={'birthday': date(1990, 9, 21)})
defaults field is using only for getting. While it is setting phase, name and surname are only set. That is what I understand from the document.
So I want to do something different that setting name,surname and birthDay, but getting name and surname excluding birthdate. I could not see the way to do that in the document and another place.
How can I do this?
Thank you!
get_or_create provides a way of getting or creating. Not saving or updating. Its idea is: I want to get a model, and if it doesn't exist, I want to create it and get it.
In Django, you don't have to worry about getting the name or the surname or any attribute. You get an instance of the model which has all the attributes, I.e.
instance = Model.objects.get(name='firstName',surname='lastName')
print instance.birthday
print instance.name
print instance.surname
An overview of the idea could be: a Model is a data structure with a set of attributes, an instance is a particular instance of a model (uniquely identified by a primary_key (pk), a number) which has a specific set of attributes (e.g. name="firstName").
Model.objects.get is used to go to the database and retrieve a specific instance with a specific attribute or set of attributes.
Since Django 1.7 there's update_or_create:
obj, created = Person.objects.update_or_create(
first_name='John',
last_name='Lennon',
defaults=updated_values
)
The parameters you give are the ones that will be used to find an existing object, the defaults are the parameters that will be updated on that existing or newly created object.
A tuple is returned, obj is the created or updated object and created is a boolean specifying whether a new object was created.
Docs: https://docs.djangoproject.com/en/1.8/ref/models/querysets/#update-or-create

Way to ensure unique constraint of a field

I have the following model class.
class Human(db.Model):
email = db.StringProperty(required=True)
date = db.DateTimeProperty(auto_now=True)
checksum = db.IntegerProperty(required=True)
version = db.IntegerProperty(required=True)
content = blobstore.BlobReferenceProperty(required=True)
Currently, to ensure the uniqueness of email in database level, (Ensure there are no duplicated email in entire database) I am using the following method.
h = human.Human(key_name='yccheok#yahoo.com', email='yccheok#yahoo.com', checksum=456, version=1281, content=blob_key)
I am not sure this is a good way to do so? Or, is there any other better way?
This is really the only way to do it.
The email property is probably redundant in this case, since you're already storing the data in the key name.
The only other option is to give all of the Human entities the same parent, thus putting them together in an entity group, which will allow you to do updates within a transaction to check for an existing entity with the same email. However, this would prevent you from making more than about 1 change to all of your Human entities (and any of their children) per second, which doesn't sound bad for a small low-traffic site but will kill scalability.

KindError in Google App Engine

I defined a simple class in GAE for keeping user profiles data like this:
class User(db.Model):
email = db.EmailProperty()
role = db.StringProperty(default=roles.USER)
first_name = db.StringProperty()
last_name = db.StringProperty()
...
I use memcache to keep session information. memcache data looks like this { 'key': 'agpjYW5kaXJhdGVzcgoLEgRVc2VyGCMM'}. I get session_id value from the cookie. When I try to get user info linked to that cookie like this:
session_id = request['session_id']
data = memcache.get(session_id)
user = User.get(data['key'])
I get KindError exception:
KindError: Kind 'User' is not a subclass of kind 'User'
I know this user exists, memcache exists. User class is defined only once in my project. Why this error occurs and how can I make it work?
UPDATE: I tried to use db.get() instead of User.get() and it worked. So, what's the problem there can be?
Model.get() does check whether the supplied key is of the correct kind, as defined in the documentation. If not of the correct kind it will throw a KindError.
db.get() does not do any type checking and therefore will succeed with the supplied value if it exists in the data store, but will not necessarily return a User entity.
So you need to check whether the key in your memcache is actually of the User kind. Are you sure it's not overwritten with the key of a different model at some point?
The App Engine framework defines a class called 'User' as part of the Users API. In addition, you have your own class by the same name. When the exception occurs, you're trying to use one, but getting the other.
To avoid this, rename your model. You should also be careful how you import modules in Python. Instead of:
from google.appengine.api.users import User
or worse:
from google.appengine.api.users import *
you should use:
from google.appengine.api import users
And then refer to users.User, which is unambiguous.
The problem, it seems to me, is more subtle than that. I was getting the error with this call to Model.get() (I'm retrieving a top-level singleton object, always there):
datastore = GDSDatastore.get(gds.Key.from_path(*path))
so I investigated with this code:
datastore = gds.get(gds.Key.from_path(*path))
if not(datastore is None or isinstance(datastore, GDSDatastore)):
logger.error("KindError isinstance(GDSDatastore)=%s class=%s" % (isinstance(datastore, GDSDatastore), datastore.__class__.__name__))
raise gds.KindError('Kind %r is not a GDSDatastore instance' %
(datastore.kind()))
The vast majority of the time I get no error, but today I got this interesting log:
KindError isinstance(GDSDatastore)=False class=GDSDatastore
Now, that strikes me as rather peculiar.
(Note: GDSDatastore is defined locally: class GDSDatastore(gds.Model))

Django: Obtaining the absolute URL without access to a request object

I have a model like the one below. When an instance is created, I want to send out an e-mail to an interested party:
class TrainStop(models.Model):
name = models.CharField(max_length=32)
notify_email = models.EmailField(null=True, blank=True)
def new_stop_created(sender, instance, created, *args, **kwargs):
# Only for new stops
if not created or instance.id is None: return
# Send the status link
if instance.notify_email:
send_mail(
subject='Stop submitted: %s' % instance.name,
message='Check status: %s' % reverse('stop_status', kwargs={'status_id':str(instance.id),}),
from_email='admin#example.com',
recipient_list=[instance.notify_email,]
)
signals.post_save.connect(new_stop_created, sender=TrainStop)
However, the reverse call only returns the path portion of the URL. Example: /stops/9/status/. I need a complete URL like http://example.com/stops/9/status/. How would I go about retrieving the hostname and port (for test instances that do not use port 80) of the current website?
My initial thought was to make this available via a variable in settings.py that I could then access as needed. However, thought someone might have a more robust suggestion.
There's the sites framework, as yedpodtrzitko mentioned, but, as you mentioned, it's very much a manual setup.
There's requiring a setting in settings.py, but it's only slightly less manual than setting up sites. (It can handle multiple domains, just as well as sites and the SITE_ID setting can).
There's an idea for replacing get_absolute_url, that would make stuff like this easier, though I think its implementation suffers from the same problem (how to get the domain, scheme [http vs https], etc).
I've been toying with the idea of a middleware that examines incoming requests and constructs a "most likely domain" setting of some sort based on the frequency of the HTTP HOST header's value. Or perhaps it could set this setting on each request individually, so you could always have the current domain to work with. I haven't gotten to the point of seriously looking into it, but it's a thought.
For getting current site there's object Site:
If you don’t have access to the request object, you can use the
get_current() method of the Site model’s manager. You should then
ensure that your settings file does contain the SITE_ID setting. This
example is equivalent to the previous one:
from django.contrib.sites.models import Site
def my_function_without_request():
current_site = Site.objects.get_current()
if current_site.domain == 'foo.com':
# Do something
pass
else:
# Do something else.
pass
More info: http://docs.djangoproject.com/en/dev/ref/contrib/sites/

Categories

Resources