I am using Django and I want a field for URLs I know there is a URLField in Django but I want that field to be a charfield and I don't want users to submit anything other than URL in that charfield
take a look at my models.py:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
email = models.EmailField(max_length=500, blank=True, null=True)
social_github = models.CharField(max_length=200, blank=True, null=True)
social_twitter = models.CharField(max_length=200, blank=True, null=True)
social_linkedin = models.CharField(max_length=200, blank=True, null=True)
social_youtube = models.CharField(max_length=200, blank=True, null=True)
social_website = models.CharField(max_length=200, blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(
default=uuid.uuid4, unique=True, primary_key=True, editable=False)
def __str__(self):
return str(self.username)
Please answer how can I make a char field behave like a URL field
An URLField is in essence just a CharField with some validation (and a default name that defaults to (a translation of) URL and a maximum length of 200. Indeed if we look at the source code [GitHub], we see:
class URLField(CharField):
default_validators = [validators.URLValidator()]
description = _("URL")
def __init__(self, verbose_name=None, name=None, **kwargs):
kwargs.setdefault('max_length', 200)
super().__init__(verbose_name, name, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if kwargs.get("max_length") == 200:
del kwargs['max_length']
return name, path, args, kwargs
def formfield(self, **kwargs):
# As with CharField, this will cause URL validation to be performed
# twice.
return super().formfield(**{
'form_class': forms.URLField,
**kwargs,
})
It also uses a different form field: the URLField is [implemented [GitHub] as):
class URLField(CharField):
widget = URLInput
# …
It will thus use a URLInput widget, but there is nothing that prevents you from using another widget. Indeed, we can implement the model with:
class Profile(models.Model):
# …
social_github = models.URLField(blank=True, null=True)
social_twitter = models.URLField(blank=True, null=True)
social_linkedin = models.URLField(blank=True, null=True)
social_youtube = models.URLField(blank=True, null=True)
social_website = models.URLField(blank=True, null=True)
# …
If you want to change the widget, for example in a ModelForm, you can work with:
class MyProfileForm(forms.ModelForm):
# …
class Meta:
# …
widgets = {
'social_github': forms.TextInput,
'social_twitter': forms.TextInput,
'social_linkedin': forms.TextInput,
'social_youtube': forms.TextInput,
'social_website': forms.TextInput
}
Related
Have the following models
class FootballWebsite(models.Model):
"""Football service website."""
url = models.URLField, unique=True)
#football service
id = models.CharField(primary_key=True,
#is this domain blocked
blocked = models.BooleanField(default=False)
#is it online or offline
online = models.BooleanField(default=False)
updated = models.DateTimeField(auto_now=True, auto_now_add=True)
sub_categories = models.ForeignKey(SubCategory, default=1)
referral = models.TextField(blank=True)
mirror = models.ForeignKey('FootballWebsite', blank=True, null=True)
rank = models.PositiveIntegerField(default=0, blank=True, null=True)
screenshot = models.BooleanField(default=False)
class Meta:
"""Meta class."""
app_label = 'ahmia'
def __unicode__(self):
return u'%s' % (self.url)
"""The datetime when the football service was last seen online"""
try:
return self.footballwebsitestatus_set.filter(online=True).latest('time').time
except FootballWebsiteStatus.DoesNotExist:
return None
class FootballWebsiteDescription(models.Model):
"""Football service website description."""
about = models.ForeignKey(Footballebsite)
title = models.TextField(blank=True, null=True)
keywords = models.TextField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
relation = models.URLField(blank=True, null=True)
subject = models.TextField(blank=True, null=True)
type = models.TextField(blank=True, null=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=True)
language = models.TextField(null=True, blank=True)
contactInformation = models.TextField(null=True, blank=True)
officialInfo = models.BooleanField(default=False)
slug = AutoSlugField(populate_from=['title'], allow_duplicates=True, null=True)
class Meta:
"""Meta class."""
app_label = 'ahmia'
def __unicode__(self):
return unicode(self.about.url)
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(FootballebsiteDescription, self).save(*args, **kwargs)
def __unicode__(self):
return u'%s' % (self.title)
I have a huge amount of links, and i would like to bulk assign them into a category or mark them as blocked based on identical title slug.
Managed to at least get a list of title_slugs with the code below, but the following step, i would like to get an inline list with all sites that have an identical title_slug and bulk assign those all in their a category
class FootballWebsiteInline(admin.TabularInline):
model = FootballWebsite
class FootballWebsiteDescriptionAdmin(admin.ModelAdmin):
list_display = ['show_slug']
def show_slug(self, obj):
return format_html("<a href='{url}'>{url}</a>", url=obj.slug)
inlines = [
FootballWebsiteInline,
]
Above code obviously doesn' t work, since the title slug which can appear many times is not a primary key.
Is it possible to get an inline list based on the title slug in this case which is not a primary key at all, or am i going about this the wrong way?
When possible at all, some further tweaking would be to group the identical title slugs
When creating the slug for my post model, I want to use the object's primary key as the slug. However when I create a new post, instance.id is NoneType and not an integer like I'd imagine.
Here is my model:
class Post(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=50, null=False, blank=False)
body = models.TextField(max_length=5000, null=False, blank=False)
image = models.ImageField(upload_to=upload_location, null=False, blank=False)
date_published = models.DateTimeField(auto_now_add=True, verbose_name="date published")
date_updated = models.DateTimeField(auto_now=True, verbose_name="date updated")
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(blank=True, unique=True)
def __str__(self):
return self.title
#receiver(post_delete, sender=Post)
def submission_delete(sender, instance, **kwargs):
instance.image.delete(False)
def pre_save_blog_post_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = slugify(instance.id)
pre_save.connect(pre_save_blog_post_receiver, sender=Post)
As you can see in pre_save_blog_post_receiver, instance.id returns as None. How do I correctly reference the primary key in this situation?
You need to use post_save in case you create a Post object, since before it is committed to the database, there is no primary key. The database "distributes" primary keys.
Slugifying with an id is however a bit "odd". The idea of a slug is to make a visually pleasant variant of the title or some other text-related attribute.
It might also be more convenient to make use of a AutoSlugField [readthedocs.io] of the django-autoslug [readthedocs.io] package:
from autoslug import AutoSlugField
class Post(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=50)
body = models.TextField(max_length=5000)
image = models.ImageField(upload_to=upload_location)
date_published = models.DateTimeField(auto_now_add=True, verbose_name='date published')
date_updated = models.DateTimeField(auto_now=True, verbose_name='date updated')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(populate_from='title')
def __str__(self):
return self.title
The view works with just the PK, however, the problem is that my PK on the live site is an incoherent string and I want to make it coherent titling for an article to boost SEO. I don't want to change the PK to the slug. I want both.
When I try to add both the PK and a slug it fails and I get the error: no reverse match.
URL path:
path('idea/<slug:slug>,<int:pk>', views.IdeaDetailView.as_view(), name='detail')
Model:
class Idea(models.Model):
idea_id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Searches ID')
idea_number = models.IntegerField(blank=True, null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
idea_title = models.CharField(max_length=300, blank=True, null=True)
idea_text = NonStrippingTextField(max_length=10000, blank=True, null=True)
Views.py:
class IdeaDetailView(generic.DetailView):
model = Idea
template_name = "idea/detail.html"
def get_context_data(self, **kwargs):
context = super(IdeaDetailView, self).get_context_data(**kwargs)
context['results'] = Idea.objects.filter(idea_id=self.kwargs.get('pk'))
return context
Admin.py:
class IdeaAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("idea_title",)}
I want to add a slug which is the idea_title, however if I try to add that into the URL it fails.
Try adding a slugfield, get_absolute_url method, and save method to your Idea model, like this:
from django.conf import settings
from django.db import models
from django.urls import reverse
from django.utils.text import slugify
class Idea(models.Model):
idea_id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Searches ID')
idea_number = models.IntegerField(blank=True, null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
idea_title = models.CharField(max_length=300, blank=True, null=True)
idea_text = NonStrippingTextField(max_length=10000, blank=True, null=True)
slug = models.SlugField(
default='',
editable=False,
max_length=300,
)
def get_absolute_url(self):
kwargs = {
'pk': self.id,
'slug': self.slug
}
return reverse('idea-pk-slug-detail', kwargs=kwargs)
def save(self, *args, **kwargs):
value = self.title
self.slug = slugify(value, allow_unicode=True)
super().save(*args, **kwargs)
Then, in urls.py:
path('idea/<int:pk>-<str:slug>/', views.IdeaDetailView.as_view(), name='detail')
And, in views.py right under template_name:
query_pk_and_slug = True
Two more methods and more info found HERE.
Hope this helps!
I have a Property Model as follows =
class Property(models.Model):
property_type = models.CharField(max_length=255, default='Apartment')
specifications = models.CharField(max_length=255, default='Basic')
built_up_area = models.FloatField(max_length=6, null=False, default=0)
total_area = models.FloatField(null=False, default=0)
number_of_bedrooms = models.CharField(max_length=3, default=1)
number_of_bathrooms = models.CharField(max_length=3, default=1)
number_of_parking_spaces = models.CharField(max_length=2, default=0)
address_line_one = models.CharField(max_length=255, null=False)
address_line_two = models.CharField(max_length=255, null=True, default=None)
connectivity = models.CharField(max_length=255, default=None, null=True)
neighborhood_quality = models.CharField(max_length=255, default=None,
null=True)
comments = models.CharField(max_length=255, default=None, null=True)
city = models.ForeignKey('City')
state = models.ForeignKey('State')
pin_code = models.ForeignKey('PinCode')
developer = models.ForeignKey('Developer', null=True, default=None)
owner = models.ForeignKey('Owner', null=True, default=None)
created_by = models.ForeignKey('custom_user.User')
project = models.ForeignKey('Project')
def __unicode__(self):
return self.property_type
class Meta:
verbose_name_plural = 'Properties'
And a City model as follows -
class City(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(City, self).save(*args, **kwargs)
def __unicode__(self):
return self.name
Now I want to make a single form where I can enter the Property details and while entering the city, I can enter the name of the city instead of selecting from the dropdown list.
So how do I create the inline formset using the inlineformset_factory to create the form?
==EDIT==
I've tried to use the following code to create the formset
CityFormset = inlineformset_factory(City, Property,
fields=('city',),
extra=0,
min_num=1,
can_delete=False)
You've misunderstood what an inline formset is. It's for editing the "many" side of a one-to-many relationship: that is, given a parent model of City, you could edit inline the various Properties that belong to that city.
You don't want a formset at all to simply edit the single City that a property can belong to. Instead, override the city field within your Property form to be a TextField, and either create a new City or find an existing one in the clean_city method.
class PropertyForm(forms.ModelForm):
city = forms.TextField(required=True)
class Meta:
model = Property
exclude = ('city',)
def __init__(self, *args, **kwargs):
super(PropertyForm, self).__init__(*args, **kwargs)
if self.instance and not self.data:
self.initial['city'] = self.instance.city.name
def save(self, commit=True):
city_name = self.cleaned_data['city']
city, _ = City.objects.get_or_create(name=city_name)
instance = self.save(commit=False)
instance.city = city
if commit = True:
instance.save()
return instance
I installed django profiles/registration and everything seems to be fine. When a user registers their profile is created also. Now what i want to do is query another Model which is Company based on the user id of User. I dont want to change django-profiles view but add the extra field on urls to match and query Company model. When i hardcode the url (ex:put the id number of the userprofile like so userprofile=1, it works.). So when a user is logged in and goes to profile detail page Company assigned to them is queried based on their user.id.
class UserProfile(models.Model):
user = models.OneToOneField(User)
#email = models.CharField(max_length=200, blank=True, null=True)
# Other fields here
#company = models.ForeignKey(Company,blank=True,null=True)
#office = models.CharField(max_length=200, blank=True, null=True)
def __unicode__(self):
return self.user.username
class Company(models.Model):
userprofile = models.ForeignKey(UserProfile, null=True, blank=True)
comp_name = models.CharField(max_length=200,blank=True,null=True)
comp_address = models.CharField(max_length=200,blank=True, null=True)
comp_email = models.CharField(max_length=200,blank=True, null=True)
comp_zip = models.IntegerField(blank=True, null=True)
comp_phone = models.IntegerField(blank=True, null=True)
comp_city = models.CharField(max_length=200,blank=True, null=True)
#comp_state = models.USStateField(blank=True, null=True
comp_state = models.CharField(blank=True, max_length=2)
compwebsite = models.URLField(max_length=200, blank=True, null=True)
twitterurl = models.URLField(max_length=200, blank=True, null=True)
facebookurl = models.URLField(max_length=200, blank=True, null=True)
def __unicode__(self):
return self.comp_name
url(r'^profiles/(?P<username>\w+)/$', 'profiles.views.profile_detail', {'extra_context':{'queryset':Company.objects.filter(userprofile=request.user.id)}},),
You might want to call it from inside a view
from *** import profile_detail
def my_view(request, username):
extra_context = {}
return profile_detail(request, queryset=Company.objects.filter(userprofile=request.user.id),
template_name="my_template.html",
paginate_by=20,
extra_context=extra_context)