I have the following model called LodgingOffer, through which it is possible to create a lodging offer and detail its data:
class LodgingOffer(models.Model):
# Foreign Key to my User model
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
ad_title = models.CharField(null=False, blank=False,
max_length=255, verbose_name='Título de la oferta')
slug = models.SlugField(max_length=100, blank=True)
country = CountryField(blank_label='(Seleccionar país)', verbose_name='Pais')
city = models.CharField(max_length=255, blank = False, verbose_name='Ciudad')
def __str__(self):
return "%s" % self.ad_title
pub_date = models.DateTimeField(auto_now_add=True,)
def get_absolute_url(self):
return reverse('host:detail', kwargs = {'slug' : self.slug })
# I assign slug to offer based in ad_title field,checking if slug exist
def create_slug(instance, new_slug=None):
slug = slugify(instance.ad_title)
if new_slug is not None:
slug = new_slug
qs = LodgingOffer.objects.filter(slug=slug).order_by("-id")
exists = qs.exists()
if exists:
new_slug = "%s-%s" % (slug, qs.first().id)
return create_slug(instance, new_slug=new_slug)
return slug
# Brefore to save, assign slug to offer created above.
def pre_save_article_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = create_slug(instance)
pre_save.connect(pre_save_article_receiver, sender=LodgingOffer)
For this model, I have a detail view called HostingOfferDetailView
in which I show the data of an offer of an objectLodgingOffer
An important objective that I want to pursue and for which I ask this question is that in the detail view of an object LodgingOffer
I must be able to contact the owner of that offer (object LodgingOffer
- user who created it-) so that another interested user can apply to it .
For this purpose, I have the function contact_owner_offer()
which is a function where I send an email to the owner of this offer.
I am doing all this in the detail view HostingOfferDetailView
in this way:
class HostingOfferDetailView(UserProfileDataMixin, LoginRequiredMixin, DetailView):
model = LodgingOffer
template_name = 'lodgingoffer_detail.html'
context_object_name = 'lodgingofferdetail'
def get_context_data(self, **kwargs):
context = super(HostingOfferDetailView, self).get_context_data(**kwargs)
user = self.request.user
# LodgingOffer object
#lodging_offer_owner = self.get_object()
# Get the full name of the lodging offer owner
lodging_offer_owner_full_name = self.get_object().created_by.get_long_name()
# Get the lodging offer email owner
lodging_offer_owner_email = self.get_object().created_by.email
# Get the lodging offer title
lodging_offer_title = self.get_object().ad_title
# Get the user interested email in lodging offer
user_interested_email = user.email
# Get the user interested full name
user_interested_full_name = user.get_long_name()
context['user_interested_email'] = user_interested_email
context['lodging_offer_owner_email'] = lodging_offer_owner_email
# Send the data (lodging_offer_owner_email
# user_interested_email and lodging_offer_title) presented
# above to the contact_owner_offer function
contact_owner_offer(self.request, lodging_offer_owner_email,
user_interested_email, lodging_offer_title)
return context
My function contact_owner_offer
receives these offer parameters and sends the email to the owner of the offer or who published it, as follows:
def contact_owner_offer(request, lodging_offer_owner_email, user_interested_email, lodging_offer_title):
user = request.user
print("a", lodging_offer_owner_email, user_interested_email)
if user.is_authenticated:
print('Send email')
mail_subject = 'Interesados en tu oferta'
context = {
'lodging_offer_owner_email': lodging_offer_owner_email,
# usuario dueño de la oferta TO
'offer': lodging_offer_title,
# oferta por la que se pregunta
'user_interested_email': user_interested_email,
# usuario interesado en la oferta
'domain': settings.SITE_URL,
'request': request
}
message = render_to_string('contact_user_own_offer.html', context)
#to_email = lodging_offer_owner.email,
send_mail(mail_subject, message, settings.DEFAULT_FROM_EMAIL,
[lodging_offer_owner_email], fail_silently=True)
# email = EmailMessage(mail_subject, message, to=[to_email])
# email.send()
# return redirect('articles:article_list')
I have done this as a test and so far everything is as I wanted, and the result is that when I enter the detail URL of an object offer LodgingOffer
, an email is sent to the owner of said offer.
What I want is that in my offer detail template, to have a button which says "Contact the owner of the offer" and that any user who presses it, immediately sends an email to the owner of the offer.
For this, I have proceeded to define a URL that calls the function contact_owner_offer()
and that is called from the attribute href
of a button in my template:
The URL, ( according to my understanding and this is where the doubt lies and the reason for my question ) I have defined according to the number of parameters that the function receivescontact_owner_offer()
This means that my URL should receive:
- The offer owner's email
- The email of the user interested in the offer
- The title of the offer, although for this I am sending you the slug of that title, I do not know if that is correct
So, according to the above, I have created this URL:
url(r'^contact-to-owner/(?P<email>[\w.@+-]+)/from/'
r'(?P<interested_email>[\w.@+-]+)/(?P<slug>[\w-]+)/$',
contact_owner_offer, name='contact_owner_offer'),
Next, in my template, I generate an html button where I call this URL by sending its respective parameters:
<div class="contact">
<a class="contact-button" href="{% url 'host:contact_owner_offer' email=lodging_offer_owner_email interested_email=user_interested_email slug=lodgingofferdetail.slug %}">
<img src="{% static 'img/icons/contact.svg' %}" alt="">
<span>Contactar</span>
</a>
</div>
What happens to me is that when I enter the offer detail template and click on the Contact button referring immediately above, I get the following error message:
TypeError: contact_owner_offer() got an unexpected keyword argument 'email'
[10/Oct/2017 01:04:06] "GET /host/contact-to-owner/[email protected]/from/[email protected]/apartacho/ HTTP/1.1" 500 77979
What I don't understand is because it tells me that my URL doesn't expect a called argument email
, which is where I pass the parameter email=lodging_offer_owner_email
through the button in the template.
I appreciate any guidance
UPDATE
According to the given recommendations I have slightly changed the definition of my URL specifying the name of the argument or keyword argument that I am passing.
My function is:
def contact_owner_offer(request, lodging_offer_owner_email, user_interested_email, slug):
user = request.user
print("a", lodging_offer_owner_email, user_interested_email, slug)
if user.is_authenticated:
print('Send email')
mail_subject = 'Interesados en tu oferta'
context = {
'lodging_offer_owner_email': lodging_offer_owner_email,
# usuario dueño de la oferta TO
'offer': slug,
# oferta por la que se pregunta
'user_interested_email': user_interested_email,
# usuario interesado en la oferta
'domain': settings.SITE_URL,
'request': request
}
message = render_to_string('contact_user_own_offer.html', context)
#to_email = lodging_offer_owner.email,
send_mail(mail_subject, message, settings.DEFAULT_FROM_EMAIL,
[lodging_offer_owner_email], fail_silently=True)
The definition of my URL has been like this:
url(r'^contact-to-owner/(?P<lodging_offer_owner_email>[\w.@+-]+)/from/'
r'(?P<interested_email>[\w.@+-]+)/(?P<slug>[\w-]+)/$',
contact_owner_offer,
name='contact_owner_offer'
),
In my html template it has been like this, the value of the slug parameter, I take it through the context_object_name that I define in the class HostingOfferDetailView
, so it remains lodgingofferdetail.slug
:
<div class="contact">
<a class="contact-button" href="{% url 'host:contact_owner_offer' lodging_offer_owner_email=lodging_offer_owner_email interested_email=user_interested_email slug=lodgingofferdetail.slug %}">
<img src="{% static 'img/icons/contact.svg' %}" alt="">
<span>Contactar</span>
</a>
</div>
And when I position myself on the button I get in the url the value of the parameters that I am handling
Only when I click that button, I get the same error again:
Traceback:
File "/home/bgarcial/.virtualenvs/hostayni/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
42. response = get_response(request)
File "/home/bgarcial/.virtualenvs/hostayni/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
187. response = self.process_exception_by_middleware(e, request)
File "/home/bgarcial/.virtualenvs/hostayni/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
Exception Type: TypeError at /host/contact-to-owner/[email protected]/from/[email protected]/apartacho/
Exception Value: contact_owner_offer() got an unexpected keyword argument 'interested_email'
It seems to me that the problem here is similar to your previous question . You have to use the same parameters in the view definition:
Don't get complicated, it's like creating any function and passing it the wrong parameters:
And that's what it does
{% url %}
, it just passes parameters to the function, but these parameters must be called the same.